summaryrefslogtreecommitdiff
path: root/libs
diff options
context:
space:
mode:
Diffstat (limited to 'libs')
-rw-r--r--libs/libcurl/docs/BINDINGS242
-rw-r--r--libs/libcurl/docs/BUGS148
-rw-r--r--libs/libcurl/docs/CHANGES5575
-rw-r--r--libs/libcurl/docs/CONTRIBUTE310
-rw-r--r--libs/libcurl/docs/COPYING21
-rw-r--r--libs/libcurl/docs/DISTRO-DILEMMA176
-rw-r--r--libs/libcurl/docs/FAQ1476
-rw-r--r--libs/libcurl/docs/FEATURES196
-rw-r--r--libs/libcurl/docs/HISTORY244
-rw-r--r--libs/libcurl/docs/HTTP-COOKIES123
-rw-r--r--libs/libcurl/docs/INSTALL1131
-rw-r--r--libs/libcurl/docs/INSTALL.devcpp302
-rw-r--r--libs/libcurl/docs/INTERNALS471
-rw-r--r--libs/libcurl/docs/KNOWN_BUGS250
-rw-r--r--libs/libcurl/docs/LICENSE-MIXING130
-rw-r--r--libs/libcurl/docs/MAIL-ETIQUETTE228
-rw-r--r--libs/libcurl/docs/MANUAL1023
-rw-r--r--libs/libcurl/docs/Makefile.am61
-rw-r--r--libs/libcurl/docs/Makefile.in819
-rw-r--r--libs/libcurl/docs/README49
-rw-r--r--libs/libcurl/docs/README.netware27
-rw-r--r--libs/libcurl/docs/README.win3226
-rw-r--r--libs/libcurl/docs/RELEASE-NOTES111
-rw-r--r--libs/libcurl/docs/RESOURCES83
-rw-r--r--libs/libcurl/docs/SSLCERTS138
-rw-r--r--libs/libcurl/docs/THANKS1063
-rw-r--r--libs/libcurl/docs/TODO700
-rw-r--r--libs/libcurl/docs/TheArtOfHttpScripting507
-rw-r--r--libs/libcurl/docs/VERSIONS60
-rw-r--r--libs/libcurl/docs/curl-config.198
-rw-r--r--libs/libcurl/docs/curl-config.html91
-rw-r--r--libs/libcurl/docs/curl-config.pdfbin0 -> 6016 bytes
-rw-r--r--libs/libcurl/docs/curl.12070
-rw-r--r--libs/libcurl/docs/curl.html961
-rw-r--r--libs/libcurl/docs/curl.pdfbin0 -> 96907 bytes
-rw-r--r--libs/libcurl/docs/index.html20
-rw-r--r--libs/libcurl/docs/mk-ca-bundle.170
-rw-r--r--libs/libcurl/docs/mk-ca-bundle.html82
-rw-r--r--libs/libcurl/docs/mk-ca-bundle.pdfbin0 -> 4957 bytes
-rw-r--r--libs/libcurl/include/README55
-rw-r--r--libs/libcurl/include/curl/curl.h2268
-rw-r--r--libs/libcurl/include/curl/curlbuild.h585
-rw-r--r--libs/libcurl/include/curl/curlrules.h262
-rw-r--r--libs/libcurl/include/curl/curlver.h69
-rw-r--r--libs/libcurl/include/curl/easy.h102
-rw-r--r--libs/libcurl/include/curl/mprintf.h81
-rw-r--r--libs/libcurl/include/curl/multi.h399
-rw-r--r--libs/libcurl/include/curl/stdcheaders.h33
-rw-r--r--libs/libcurl/include/curl/typecheck-gcc.h609
-rw-r--r--libs/libcurl/libcurl.vcxproj37
-rw-r--r--libs/libcurl/libcurl.vcxproj.filters4
-rw-r--r--libs/libcurl/src/README.ares69
-rw-r--r--libs/libcurl/src/README.curl_off_t68
-rw-r--r--libs/libcurl/src/README.curlx61
-rw-r--r--libs/libcurl/src/README.encoding60
-rw-r--r--libs/libcurl/src/README.hostip35
-rw-r--r--libs/libcurl/src/README.httpauth74
-rw-r--r--libs/libcurl/src/README.memoryleak55
-rw-r--r--libs/libcurl/src/README.multi_socket53
-rw-r--r--libs/libcurl/src/README.pingpong30
-rw-r--r--libs/libcurl/src/README.pipelining51
-rw-r--r--libs/libcurl/src/amigaos.c77
-rw-r--r--libs/libcurl/src/amigaos.h39
-rw-r--r--libs/libcurl/src/arpa_telnet.h104
-rw-r--r--libs/libcurl/src/asyn-ares.c694
-rw-r--r--libs/libcurl/src/asyn-thread.c662
-rw-r--r--libs/libcurl/src/asyn.h168
-rw-r--r--libs/libcurl/src/axtls.c661
-rw-r--r--libs/libcurl/src/axtls.h68
-rw-r--r--libs/libcurl/src/base64.c248
-rw-r--r--libs/libcurl/src/bundles.c110
-rw-r--r--libs/libcurl/src/bundles.h45
-rw-r--r--libs/libcurl/src/checksrc.pl198
-rw-r--r--libs/libcurl/src/config-amigaos.h167
-rw-r--r--libs/libcurl/src/config-dos.h188
-rw-r--r--libs/libcurl/src/config-mac.h126
-rw-r--r--libs/libcurl/src/config-os400.h551
-rw-r--r--libs/libcurl/src/config-riscos.h513
-rw-r--r--libs/libcurl/src/config-symbian.h818
-rw-r--r--libs/libcurl/src/config-tpf.h773
-rw-r--r--libs/libcurl/src/config-vxworks.h934
-rw-r--r--libs/libcurl/src/config-win32.h681
-rw-r--r--libs/libcurl/src/config-win32ce.h448
-rw-r--r--libs/libcurl/src/conncache.c280
-rw-r--r--libs/libcurl/src/conncache.h53
-rw-r--r--libs/libcurl/src/connect.c1331
-rw-r--r--libs/libcurl/src/connect.h107
-rw-r--r--libs/libcurl/src/content_encoding.c435
-rw-r--r--libs/libcurl/src/content_encoding.h48
-rw-r--r--libs/libcurl/src/cookie.c1319
-rw-r--r--libs/libcurl/src/cookie.h104
-rw-r--r--libs/libcurl/src/curl_addrinfo.c527
-rw-r--r--libs/libcurl/src/curl_addrinfo.h97
-rw-r--r--libs/libcurl/src/curl_base64.h32
-rw-r--r--libs/libcurl/src/curl_darwinssl.c2125
-rw-r--r--libs/libcurl/src/curl_darwinssl.h78
-rw-r--r--libs/libcurl/src/curl_fnmatch.c427
-rw-r--r--libs/libcurl/src/curl_fnmatch.h44
-rw-r--r--libs/libcurl/src/curl_gethostname.c100
-rw-r--r--libs/libcurl/src/curl_gethostname.h31
-rw-r--r--libs/libcurl/src/curl_gssapi.c69
-rw-r--r--libs/libcurl/src/curl_gssapi.h57
-rw-r--r--libs/libcurl/src/curl_hmac.h67
-rw-r--r--libs/libcurl/src/curl_ldap.h35
-rw-r--r--libs/libcurl/src/curl_md4.h33
-rw-r--r--libs/libcurl/src/curl_md5.h63
-rw-r--r--libs/libcurl/src/curl_memory.h140
-rw-r--r--libs/libcurl/src/curl_memrchr.c62
-rw-r--r--libs/libcurl/src/curl_memrchr.h44
-rw-r--r--libs/libcurl/src/curl_multibyte.c82
-rw-r--r--libs/libcurl/src/curl_multibyte.h90
-rw-r--r--libs/libcurl/src/curl_ntlm.c244
-rw-r--r--libs/libcurl/src/curl_ntlm.h44
-rw-r--r--libs/libcurl/src/curl_ntlm_core.c436
-rw-r--r--libs/libcurl/src/curl_ntlm_core.h68
-rw-r--r--libs/libcurl/src/curl_ntlm_msgs.c920
-rw-r--r--libs/libcurl/src/curl_ntlm_msgs.h178
-rw-r--r--libs/libcurl/src/curl_ntlm_wb.c391
-rw-r--r--libs/libcurl/src/curl_ntlm_wb.h37
-rw-r--r--libs/libcurl/src/curl_rtmp.c310
-rw-r--r--libs/libcurl/src/curl_rtmp.h33
-rw-r--r--libs/libcurl/src/curl_sasl.c539
-rw-r--r--libs/libcurl/src/curl_sasl.h115
-rw-r--r--libs/libcurl/src/curl_schannel.c1308
-rw-r--r--libs/libcurl/src/curl_schannel.h132
-rw-r--r--libs/libcurl/src/curl_sec.h51
-rw-r--r--libs/libcurl/src/curl_setup.h707
-rw-r--r--libs/libcurl/src/curl_setup_once.h551
-rw-r--r--libs/libcurl/src/curl_sspi.c126
-rw-r--r--libs/libcurl/src/curl_sspi.h293
-rw-r--r--libs/libcurl/src/curl_threads.c129
-rw-r--r--libs/libcurl/src/curl_threads.h57
-rw-r--r--libs/libcurl/src/curlx.h119
-rw-r--r--libs/libcurl/src/cyassl.c611
-rw-r--r--libs/libcurl/src/cyassl.h64
-rw-r--r--libs/libcurl/src/dict.c284
-rw-r--r--libs/libcurl/src/dict.h29
-rw-r--r--libs/libcurl/src/dotdot.c170
-rw-r--r--libs/libcurl/src/dotdot.h25
-rw-r--r--libs/libcurl/src/easy.c1223
-rw-r--r--libs/libcurl/src/easyif.h33
-rw-r--r--libs/libcurl/src/escape.c234
-rw-r--r--libs/libcurl/src/escape.h33
-rw-r--r--libs/libcurl/src/file.c582
-rw-r--r--libs/libcurl/src/file.h41
-rw-r--r--libs/libcurl/src/fileinfo.c54
-rw-r--r--libs/libcurl/src/fileinfo.h33
-rw-r--r--libs/libcurl/src/formdata.c1594
-rw-r--r--libs/libcurl/src/formdata.h98
-rw-r--r--libs/libcurl/src/ftp.c4569
-rw-r--r--libs/libcurl/src/ftp.h154
-rw-r--r--libs/libcurl/src/ftplistparser.c1050
-rw-r--r--libs/libcurl/src/ftplistparser.h41
-rw-r--r--libs/libcurl/src/getenv.c53
-rw-r--r--libs/libcurl/src/getinfo.c331
-rw-r--r--libs/libcurl/src/getinfo.h27
-rw-r--r--libs/libcurl/src/gopher.c169
-rw-r--r--libs/libcurl/src/gopher.h29
-rw-r--r--libs/libcurl/src/gskit.c906
-rw-r--r--libs/libcurl/src/gskit.h64
-rw-r--r--libs/libcurl/src/gtls.c1119
-rw-r--r--libs/libcurl/src/gtls.h81
-rw-r--r--libs/libcurl/src/hash.c400
-rw-r--r--libs/libcurl/src/hash.h106
-rw-r--r--libs/libcurl/src/hmac.c133
-rw-r--r--libs/libcurl/src/hostasyn.c157
-rw-r--r--libs/libcurl/src/hostcheck.c97
-rw-r--r--libs/libcurl/src/hostcheck.h32
-rw-r--r--libs/libcurl/src/hostip.c827
-rw-r--r--libs/libcurl/src/hostip.h239
-rw-r--r--libs/libcurl/src/hostip4.c310
-rw-r--r--libs/libcurl/src/hostip6.c224
-rw-r--r--libs/libcurl/src/hostsyn.c111
-rw-r--r--libs/libcurl/src/http.c3527
-rw-r--r--libs/libcurl/src/http.h186
-rw-r--r--libs/libcurl/src/http2.c182
-rw-r--r--libs/libcurl/src/http2.h42
-rw-r--r--libs/libcurl/src/http_chunks.c397
-rw-r--r--libs/libcurl/src/http_chunks.h108
-rw-r--r--libs/libcurl/src/http_digest.c604
-rw-r--r--libs/libcurl/src/http_digest.h57
-rw-r--r--libs/libcurl/src/http_negotiate.c388
-rw-r--r--libs/libcurl/src/http_negotiate.h42
-rw-r--r--libs/libcurl/src/http_negotiate_sspi.c308
-rw-r--r--libs/libcurl/src/http_proxy.c571
-rw-r--r--libs/libcurl/src/http_proxy.h41
-rw-r--r--libs/libcurl/src/idn_win32.c85
-rw-r--r--libs/libcurl/src/if2ip.c218
-rw-r--r--libs/libcurl/src/if2ip.h74
-rw-r--r--libs/libcurl/src/imap.c2452
-rw-r--r--libs/libcurl/src/imap.h94
-rw-r--r--libs/libcurl/src/inet_ntop.c199
-rw-r--r--libs/libcurl/src/inet_ntop.h38
-rw-r--r--libs/libcurl/src/inet_pton.c234
-rw-r--r--libs/libcurl/src/inet_pton.h37
-rw-r--r--libs/libcurl/src/krb4.c440
-rw-r--r--libs/libcurl/src/krb4.h57
-rw-r--r--libs/libcurl/src/krb5.c341
-rw-r--r--libs/libcurl/src/ldap.c708
-rw-r--r--libs/libcurl/src/libcurl.rc63
-rw-r--r--libs/libcurl/src/llist.c212
-rw-r--r--libs/libcurl/src/llist.h57
-rw-r--r--libs/libcurl/src/md4.c282
-rw-r--r--libs/libcurl/src/md5.c541
-rw-r--r--libs/libcurl/src/memdebug.c489
-rw-r--r--libs/libcurl/src/memdebug.h176
-rw-r--r--libs/libcurl/src/mk-ca-bundle.pl223
-rw-r--r--libs/libcurl/src/mprintf.c1098
-rw-r--r--libs/libcurl/src/multi.c2702
-rw-r--r--libs/libcurl/src/multihandle.h139
-rw-r--r--libs/libcurl/src/multiif.h104
-rw-r--r--libs/libcurl/src/netrc.c188
-rw-r--r--libs/libcurl/src/netrc.h36
-rw-r--r--libs/libcurl/src/non-ascii.c343
-rw-r--r--libs/libcurl/src/non-ascii.h63
-rw-r--r--libs/libcurl/src/nonblock.c91
-rw-r--r--libs/libcurl/src/nonblock.h31
-rw-r--r--libs/libcurl/src/nss.c1574
-rw-r--r--libs/libcurl/src/nssg.h88
-rw-r--r--libs/libcurl/src/nwlib.c329
-rw-r--r--libs/libcurl/src/nwos.c88
-rw-r--r--libs/libcurl/src/openldap.c639
-rw-r--r--libs/libcurl/src/parsedate.c580
-rw-r--r--libs/libcurl/src/parsedate.h31
-rw-r--r--libs/libcurl/src/pingpong.c519
-rw-r--r--libs/libcurl/src/pingpong.h150
-rw-r--r--libs/libcurl/src/pipeline.c333
-rw-r--r--libs/libcurl/src/pipeline.h46
-rw-r--r--libs/libcurl/src/polarssl.c706
-rw-r--r--libs/libcurl/src/polarssl.h67
-rw-r--r--libs/libcurl/src/polarssl_threadlock.c156
-rw-r--r--libs/libcurl/src/polarssl_threadlock.h53
-rw-r--r--libs/libcurl/src/pop3.c1996
-rw-r--r--libs/libcurl/src/pop3.h105
-rw-r--r--libs/libcurl/src/progress.c483
-rw-r--r--libs/libcurl/src/progress.h72
-rw-r--r--libs/libcurl/src/qssl.c521
-rw-r--r--libs/libcurl/src/qssl.h61
-rw-r--r--libs/libcurl/src/rawstr.c142
-rw-r--r--libs/libcurl/src/rawstr.h47
-rw-r--r--libs/libcurl/src/rtsp.c809
-rw-r--r--libs/libcurl/src/rtsp.h69
-rw-r--r--libs/libcurl/src/security.c601
-rw-r--r--libs/libcurl/src/select.c516
-rw-r--r--libs/libcurl/src/select.h114
-rw-r--r--libs/libcurl/src/sendf.c678
-rw-r--r--libs/libcurl/src/sendf.h90
-rw-r--r--libs/libcurl/src/setup-os400.h230
-rw-r--r--libs/libcurl/src/setup-vms.h399
-rw-r--r--libs/libcurl/src/share.c254
-rw-r--r--libs/libcurl/src/share.h61
-rw-r--r--libs/libcurl/src/slist.c143
-rw-r--r--libs/libcurl/src/slist.h40
-rw-r--r--libs/libcurl/src/smtp.c1921
-rw-r--r--libs/libcurl/src/smtp.h98
-rw-r--r--libs/libcurl/src/sockaddr.h43
-rw-r--r--libs/libcurl/src/socks.c751
-rw-r--r--libs/libcurl/src/socks.h77
-rw-r--r--libs/libcurl/src/socks_gssapi.c533
-rw-r--r--libs/libcurl/src/socks_sspi.c591
-rw-r--r--libs/libcurl/src/speedcheck.c74
-rw-r--r--libs/libcurl/src/speedcheck.h33
-rw-r--r--libs/libcurl/src/splay.c288
-rw-r--r--libs/libcurl/src/splay.h66
-rw-r--r--libs/libcurl/src/ssh.c3271
-rw-r--r--libs/libcurl/src/ssh.h183
-rw-r--r--libs/libcurl/src/sslgen.c676
-rw-r--r--libs/libcurl/src/sslgen.h126
-rw-r--r--libs/libcurl/src/ssluse.c2696
-rw-r--r--libs/libcurl/src/ssluse.h99
-rw-r--r--libs/libcurl/src/stdafx.cxx2
-rw-r--r--libs/libcurl/src/stdafx.h2
-rw-r--r--libs/libcurl/src/strdup.c52
-rw-r--r--libs/libcurl/src/strdup.h30
-rw-r--r--libs/libcurl/src/strequal.c79
-rw-r--r--libs/libcurl/src/strequal.h31
-rw-r--r--libs/libcurl/src/strerror.c1125
-rw-r--r--libs/libcurl/src/strerror.h37
-rw-r--r--libs/libcurl/src/strtok.c66
-rw-r--r--libs/libcurl/src/strtok.h34
-rw-r--r--libs/libcurl/src/strtoofft.c188
-rw-r--r--libs/libcurl/src/strtoofft.h68
-rw-r--r--libs/libcurl/src/telnet.c1678
-rw-r--r--libs/libcurl/src/telnet.h29
-rw-r--r--libs/libcurl/src/tftp.c1370
-rw-r--r--libs/libcurl/src/tftp.h29
-rw-r--r--libs/libcurl/src/timeval.c134
-rw-r--r--libs/libcurl/src/timeval.h58
-rw-r--r--libs/libcurl/src/transfer.c1976
-rw-r--r--libs/libcurl/src/transfer.h70
-rw-r--r--libs/libcurl/src/url.c5953
-rw-r--r--libs/libcurl/src/url.h82
-rw-r--r--libs/libcurl/src/urldata.h1648
-rw-r--r--libs/libcurl/src/version.c349
-rw-r--r--libs/libcurl/src/warnless.c453
-rw-r--r--libs/libcurl/src/warnless.h90
-rw-r--r--libs/libcurl/src/wildcard.c77
-rw-r--r--libs/libcurl/src/wildcard.h58
-rw-r--r--libs/libcurl/src/x509asn1.c1151
-rw-r--r--libs/libcurl/src/x509asn1.h129
-rw-r--r--libs/libjson/libjson.vcxproj.filters457
301 files changed, 123052 insertions, 457 deletions
diff --git a/libs/libcurl/docs/BINDINGS b/libs/libcurl/docs/BINDINGS
new file mode 100644
index 0000000000..466c36bd0f
--- /dev/null
+++ b/libs/libcurl/docs/BINDINGS
@@ -0,0 +1,242 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ libcurl bindings
+
+ Creative people have written bindings or interfaces for various environments
+ and programming languages. Using one of these allows you to take advantage of
+ curl powers from within your favourite language or system.
+
+ This is a list of all known interfaces as of this writing.
+
+ The bindings listed below are not part of the curl/libcurl distribution
+ archives, but must be downloaded and installed separately.
+
+Ada95
+
+ Writtten by Andreas Almroth
+ http://www.almroth.com/adacurl/index.html
+
+Basic
+
+ ScriptBasic bindings to libcurl. Writtten by Peter Verhas
+ http://scriptbasic.com/
+
+C
+ libcurl is a C library in itself!
+ http://curl.haxx.se/libcurl/
+
+C++
+
+ Written by Jean-Philippe Barrette-LaPierre
+ http://curlpp.org/
+
+Ch
+
+ Written by Stephen Nestinger and Jonathan Rogado
+ http://chcurl.sourceforge.net/
+
+Cocoa
+
+ BBHTTP: written by Bruno de Carvalho
+ https://github.com/brunodecarvalho/BBHTTP
+
+ curlhandle: Written by Dan Wood
+ http://curlhandle.sourceforge.net/
+
+D
+
+ Written by Kenneth Bogert
+ http://curl.haxx.se/libcurl/d/
+
+Dylan
+
+ Written by Chris Double
+ http://dylanlibs.sourceforge.net/
+
+Eiffel
+
+ Written by Eiffel Software
+ http://curl.haxx.se/libcurl/eiffel/
+
+Euphoria
+
+ Written by Ray Smith
+ http://rays-web.com/eulibcurl.htm
+
+Falcon
+
+ http://www.falconpl.org/index.ftd?page_id=prjs&prj_id=curl
+
+Ferite
+
+ Written by Paul Querna
+ http://www.ferite.org/
+
+Gambas
+
+ http://gambas.sourceforge.net
+
+glib/GTK+
+
+ Written by Richard Atterer
+ http://atterer.net/glibcurl/
+
+Guile:
+
+ Written by Michael L. Gran
+ http://www.lonelycactus.com/guile-curl.html
+
+Haskell
+
+ Written by Galois, Inc
+ http://hackage.haskell.org/cgi-bin/hackage-scripts/package/curl
+
+Java
+
+ Maintained by [blank]
+ http://curl.haxx.se/libcurl/java/
+
+Julia
+
+ Written by Paul Howe
+ https://github.com/forio/Curl.jl
+
+Lisp
+
+ Written by Liam Healy
+ http://common-lisp.net/project/cl-curl/
+
+Lua
+
+ luacurl by Alexander Marinov
+ http://luacurl.luaforge.net/
+
+ Lua-cURL by Jrgen Htzel
+ http://luaforge.net/projects/lua-curl/
+
+Mono
+
+ Written by Jeffrey Phillips
+ http://forge.novell.com/modules/xfmod/project/?libcurl-mono
+
+.NET
+
+ libcurl-net by Jeffrey Phillips
+ http://sourceforge.net/projects/libcurl-net/
+
+Object-Pascal
+
+ Free Pascal, Delphi and Kylix binding written by Christophe Espern.
+ http://www.tekool.com/opcurl
+
+O'Caml
+
+ Written by Lars Nilsson
+ http://sourceforge.net/projects/ocurl/
+
+Pascal
+
+ Free Pascal, Delphi and Kylix binding written by Jeffrey Pohlmeyer.
+ http://houston.quik.com/jkp/curlpas/
+
+Perl
+
+ Maintained by Cris Bailiff
+ http://curl.haxx.se/libcurl/perl/
+
+PHP
+
+ Written by Sterling Hughes
+ http://curl.haxx.se/libcurl/php/
+
+PostgreSQL
+
+ Written by Gian Paolo Ciceri
+ http://gborg.postgresql.org/project/pgcurl/projdisplay.php
+
+Python
+
+ PycURL by Kjetil Jacobsen
+ http://pycurl.sourceforge.net/
+
+R
+
+ RCurl by Duncan Temple Lang
+ http://www.omegahat.org/RCurl/
+
+Rexx
+
+ Written Mark Hessling
+ http://rexxcurl.sourceforge.net/
+
+RPG
+
+ Support for ILE/RPG on OS/400 is included in source distribution
+ http://curl.haxx.se/libcurl/
+ See packages/OS400/README.OS400 and packages/OS400/curl.inc.in
+
+Ruby
+
+ curb - written by Ross Bamford
+ http://curb.rubyforge.org/
+
+ ruby-curl-multi - written by Kristjan Petursson and Keith Rarick
+ http://curl-multi.rubyforge.org/
+
+Scheme
+
+ Bigloo binding by Kirill Lisovsky
+ http://curl.haxx.se/libcurl/scheme/
+
+S-Lang
+
+ S-Lang binding by John E Davis
+ http://www.jedsoft.org/slang/modules/curl.html
+
+Smalltalk
+
+ Smalltalk binding by Danil Osipchuk
+ http://www.squeaksource.com/CurlPlugin/
+
+SP-Forth
+
+ SP-Forth binding by ygrek
+ http://www.forth.org.ru/~ac/lib/lin/curl/
+
+SPL
+
+ SPL binding by Clifford Wolf
+ http://www.clifford.at/spl/
+
+Tcl
+
+ Tclcurl by Andrs Garca
+ http://personal1.iddeo.es/andresgarci/tclcurl/english/docs.html
+
+Visual Basic
+
+ libcurl-vb by Jeffrey Phillips
+ http://sourceforge.net/projects/libcurl-vb/
+
+Visual Foxpro
+
+ by Carlos Alloatti
+ http://www.ctl32.com.ar/libcurl.asp
+
+Q
+ The libcurl module is part of the default install
+ http://q-lang.sourceforge.net/
+
+wxWidgets
+
+ Written by Casey O'Donnell
+ http://wxcode.sourceforge.net/components/wxcurl/
+
+XBLite
+
+ Written by David Szafranski
+ http://perso.wanadoo.fr/xblite/libraries.html
diff --git a/libs/libcurl/docs/BUGS b/libs/libcurl/docs/BUGS
new file mode 100644
index 0000000000..c0c6fa82a9
--- /dev/null
+++ b/libs/libcurl/docs/BUGS
@@ -0,0 +1,148 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+BUGS
+
+ 1. Bugs
+ 1.1 There are still bugs
+ 1.2 Where to report
+ 1.3 What to report
+ 1.4 libcurl problems
+ 1.5 Who will fix the problems
+ 1.6 How to get a stack trace
+ 1.7 Bugs in libcurl bindings
+
+==============================================================================
+
+1.1 There are still bugs
+
+ Curl and libcurl have grown substantially since the beginning. At the time
+ of writing (January 2013), there are about 83,000 lines of source code, and
+ by the time you read this it has probably grown even more.
+
+ Of course there are lots of bugs left. And lots of misfeatures.
+
+ To help us make curl the stable and solid product we want it to be, we need
+ bug reports and bug fixes.
+
+1.2 Where to report
+
+ If you can't fix a bug yourself and submit a fix for it, try to report an as
+ detailed report as possible to a curl mailing list to allow one of us to
+ have a go at a solution. You can optionally also post your bug/problem at
+ curl's bug tracking system over at
+
+ https://sourceforge.net/p/curl/bugs/
+
+ Please read the rest of this document below first before doing that! Also,
+ you need to login to your sourceforge account before being able to submit a
+ bug report (necessary evil done to avoid spam).
+
+ If you feel you need to ask around first, find a suitable mailing list and
+ post there. The lists are available on http://curl.haxx.se/mail/
+
+1.3 What to report
+
+ When reporting a bug, you should include all information that will help us
+ understand what's wrong, what you expected to happen and how to repeat the
+ bad behavior. You therefore need to tell us:
+
+ - your operating system's name and version number
+
+ - what version of curl you're using (curl -V is fine)
+
+ - versions of the used libraries that libcurl is built to use
+
+ - what URL you were working with (if possible), at least which protocol
+
+ and anything and everything else you think matters. Tell us what you
+ expected to happen, tell use what did happen, tell us how you could make it
+ work another way. Dig around, try out, test. Then include all the tiny bits
+ and pieces in your report. You will benefit from this yourself, as it will
+ enable us to help you quicker and more accurately.
+
+ Since curl deals with networks, it often helps us if you include a protocol
+ debug dump with your bug report. The output you get by using the -v or
+ --trace options.
+
+ If curl crashed, causing a core dump (in unix), there is hardly any use to
+ send that huge file to anyone of us. Unless we have an exact same system
+ setup as you, we can't do much with it. Instead we ask you to get a stack
+ trace and send that (much smaller) output to us instead!
+
+ The address and how to subscribe to the mailing lists are detailed in the
+ MANUAL file.
+
+1.4 libcurl problems
+
+ First, post all libcurl problems on the curl-library mailing list.
+
+ When you've written your own application with libcurl to perform transfers,
+ it is even more important to be specific and detailed when reporting bugs.
+
+ Tell us the libcurl version and your operating system. Tell us the name and
+ version of all relevant sub-components like for example the SSL library
+ you're using and what name resolving your libcurl uses. If you use SFTP or
+ SCP, the libssh2 version is relevant etc.
+
+ Showing us a real source code example repeating your problem is the best way
+ to get our attention and it will greatly increase our chances to understand
+ your problem and to work on a fix (if we agree it truly is a problem).
+
+ Lots of problems that appear to be libcurl problems are actually just abuses
+ of the libcurl API or other malfunctions in your applications. It is advised
+ that you run your problematic program using a memory debug tool like
+ valgrind or similar before you post memory-related or "crashing" problems to
+ us.
+
+1.5 Who will fix the problems
+
+ If the problems or bugs you describe are considered to be bugs, we want to
+ have the problems fixed.
+
+ There are no developers in the curl project that are paid to work on bugs.
+ All developers that take on reported bugs do this on a voluntary basis. We
+ do it out of an ambition to keep curl and libcurl excellent products and out
+ of pride.
+
+ But please do not assume that you can just lump over something to us and it
+ will then magically be fixed after some given time. Most often we need
+ feedback and help to understand what you've experienced and how to repeat a
+ problem. Then we may only be able to assist YOU to debug the problem and to
+ track down the proper fix.
+
+ We get reports from many people every month and each report can take a
+ considerable amount of time to really go to the bottom with.
+
+1.6 How to get a stack trace
+
+ First, you must make sure that you compile all sources with -g and that you
+ don't 'strip' the final executable. Try to avoid optimizing the code as
+ well, remove -O, -O2 etc from the compiler options.
+
+ Run the program until it cores.
+
+ Run your debugger on the core file, like '<debugger> curl core'. <debugger>
+ should be replaced with the name of your debugger, in most cases that will
+ be 'gdb', but 'dbx' and others also occur.
+
+ When the debugger has finished loading the core file and presents you a
+ prompt, enter 'where' (without the quotes) and press return.
+
+ The list that is presented is the stack trace. If everything worked, it is
+ supposed to contain the chain of functions that were called when curl
+ crashed. Include the stack trace with your detailed bug report. It'll help a
+ lot.
+
+1.7 Bugs in libcurl bindings
+
+ There will of course pop up bugs in libcurl bindings. You should then
+ primarily approach the team that works on that particular binding and see
+ what you can do to help them fix the problem.
+
+ If you suspect that the problem exists in the underlying libcurl, then
+ please convert your program over to plain C and follow the steps outlined
+ above.
diff --git a/libs/libcurl/docs/CHANGES b/libs/libcurl/docs/CHANGES
new file mode 100644
index 0000000000..a384fadba8
--- /dev/null
+++ b/libs/libcurl/docs/CHANGES
@@ -0,0 +1,5575 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ Changelog
+
+Version 7.33.0 (13 Oct 2013)
+
+Daniel Stenberg (13 Oct 2013)
+- RELEASE-NOTES: synced with 92cf6141ed0de
+
+- curl: fix --oauth2-bearer in the --help output
+
+ After the option rename in 5df04bfafd1
+
+- OpenSSL: improve the grammar of the language in 39beaa5ffbcc
+
+ Reported-by: Petr Pisar
+
+- [Andrej E Baranov brought this change]
+
+ OpenSSL: use failf() when subjectAltName mismatches
+
+ Write to CURLOPT_ERRORBUFFER information about mismatch alternative
+ certificate subject names.
+
+ Signed-off-by: Andrej E Baranov <admin@andrej-andb.ru>
+
+- curl: rename --bearer to --oauth2-bearer
+
+ The option '--bearer' might be slightly ambiguous in name. It doesn't
+ create any conflict that I am aware of at the moment, however, OAUTH v2
+ is not the only authentication mechanism which uses "bearer" tokens.
+
+ Reported-by: Kyle L. Huff
+ URL: http://curl.haxx.se/mail/lib-2013-10/0064.html
+
+- [Kamil Dudka brought this change]
+
+ ssh: improve the logic for detecting blocking direction
+
+ This fixes a regression introduced by commit 0feeab78 limiting the speed
+ of SCP upload to 16384 B/s on a fast connection (such as localhost).
+
+Dan Fandrich (12 Oct 2013)
+- Fixed typo in Makefile.inc that left http2.h out of the tar ball
+
+Daniel Stenberg (11 Oct 2013)
+- [Heinrich Schaefer brought this change]
+
+ minor fix in doc
+
+- [Gisle Vanem brought this change]
+
+ curl_setup_once: fix errno access for lwip on Windows
+
+ lib/curl_setup_once.h assumed lwIP on Windows uses 'SetLastError()' to
+ set network errors. It doesn't; it uses 'errno'.
+
+- test1239: verify 4cd444e01ad and the simulated 304 response
+
+- [Derek Higgins brought this change]
+
+ HTTP: Output http response 304 when modified time is too old
+
+ When using the -w '%{http_code}' flag and simulating a Not Modified then
+ 304 should be output.
+
+- contributors: helper script to dig out contributors from git
+
+- RELEASE-NOTES: add twos refs to bug reports
+
+- RELEASE-NOTES: synced with 173160c0d068
+
+Nick Zitzmann (2 Oct 2013)
+- darwinssl: block TLS_RSA_WITH_NULL_SHA256 cipher
+
+ Credit (for catching a cipher I forgot to add to the blocked ciphers list):
+ https://www.ssllabs.com/ssltest/viewMyClient.html
+
+Daniel Stenberg (2 Oct 2013)
+- OpenSSL: acknowledge CURLOPT_SSL_VERIFYHOST without VERIFYPEER
+
+ Setting only CURLOPT_SSL_VERIFYHOST without CURLOPT_SSL_VERIFYPEER set
+ should still verify that the host name fields in the server certificate
+ is fine or return failure.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-10/0002.html
+ Reported-by: Ishan SinghLevett
+
+- KNOWN_BUGS: #84: CURLINFO_SSL_VERIFYRESULT
+
+ CURLINFO_SSL_VERIFYRESULT is only implemented for the OpenSSL and NSS
+ backends and not for any other!
+
+- [François Charlier brought this change]
+
+ xattr: add support for FreeBSD xattr API
+
+- curl_easy_setopt.3: slight clarification of SEEKFUNCTION
+
+Steve Holme (29 Sep 2013)
+- tests: Fixed typos from commit 25a0c96a494297
+
+- tests: Updated email addresses in SMTP tests following recent changes
+
+- test909: Removed custom EHLO response after recent changes
+
+ ...as it is no longer required following capability and authentication
+ changes and is now causing problems following commit 49341628b50007 as
+ the test number is obtained from the client address in the EHLO.
+
+- ftpserver.pl: Fixed compilation error from commit 49341628b50007
+
+- ftpserver.pl: Moved specifying the test number from the RCPT address
+
+ ...to the client address as this frees the RCPT strings to contain
+ just an email address and by passing the test number into curl as the
+ client address remains consistent with POP3 and IMAP tests as they are
+ specified in the URL.
+
+- ftpserver.pl: Added unwanted argument check to SMTP DATA command handler
+
+Daniel Stenberg (29 Sep 2013)
+- getinmemory: remove a comment
+
+ The comment mentioned the need to free the data, but the example already
+ does that free
+
+- postinmemory: new example
+
+ This is similar to getinmemory.c but with an initial POST.
+
+ Combined-by: Ulf Samuelsson
+
+- win32: fix Visual Studio 2010 build with WINVER >= 0x600
+
+ If no WINVER and/or _WIN32_IWNNT define was set, the Windows platform
+ SDK often defaults to high value, e.g. 0x601 (whoch may probably depend
+ on the Windows version being used, in my case Windows 7).
+
+ If WINVER >= 0x600 then winsock2.h includes some defines for WSAPoll(),
+ e.g. POLLIN, POLLPRI, POLLOUT etc. These defines clash with cURL's
+ lib/select.h.
+
+ Make sure HAVE_STRUCT_POLLFD is defined then.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1282
+ Reported-by: "kdekker"
+ Patch-by: Marcel Raad
+
+Steve Holme (28 Sep 2013)
+- ssluse.c: Fixed compilation warnings when ENGINE not supported
+
+ The function "ssl_ui_reader" was declared but never referenced
+ The function "ssl_ui_writer" was declared but never referenced
+
+Daniel Stenberg (27 Sep 2013)
+- configure: use icc options without space
+
+ The latest version(s) of the icc compiler no longer accept the extra
+ space in the -we (warning enable), -wd (warning disable), etc.
+
+ Reported-by: Elmira A Semenova
+ Bug: http://curl.haxx.se/mail/lib-2013-09/0182.html
+
+Steve Holme (25 Sep 2013)
+- imap: Added clarification to the code about odd continuation responses
+
+- ftp.c: Fixed compilation warning
+
+ There is an implicit conversion from "unsigned long" to "long"
+
+- sasl: Centralised the authentication mechanism strings
+
+ Moved the standard SASL mechanism strings into curl_sasl.h rather than
+ hard coding the same values over and over again in the protocols that
+ use SASL authentication.
+
+ For more information about the mechanism strings see:
+
+ http://www.iana.org/assignments/sasl-mechanisms
+
+Daniel Stenberg (23 Sep 2013)
+- RELEASE-NOTES: added recent contributors missing
+
+Steve Holme (23 Sep 2013)
+- test906: Fixed type-2 response
+
+- test915: Corrected test number from commit 22bccb0edaf041
+
+- test906: Fixed type-1 message not handled error
+
+ ...from commit f81d1e16664976 due to copy paste error.
+
+- tests: Added SMTP AUTH NTLM test
+
+- tests: Added SMTP multiple and invalid --mail-rcpt test
+
+- tests: Added SMTP multiple --mail-rcpt test
+
+- tests: Added SMTP invalid --mail-rcpt test
+
+- tests: Regrouping of SMTP tests
+
+Daniel Stenberg (22 Sep 2013)
+- [Benoit Sigoure brought this change]
+
+ test1112: Increase the timeout from 7s to 16s
+
+ As someone reported on the mailing list a while back, the hard-coded
+ arbitrary timeout of 7s in test 1112 is not sufficient in some build
+ environments. At Arista Networks we build and test curl as part of our
+ automated build system, and we've run into this timeout 170 times so
+ far. Our build servers are typically quite busy building and testing a
+ lot of code in parallel, so despite being beefy machines with 32 cores
+ and 128GB of RAM we still hit this 7s timeout regularly.
+
+ URL: http://curl.haxx.se/mail/lib-2010-02/0200.html
+
+Steve Holme (22 Sep 2013)
+- tests: Fixed smtp rcpt to addresses
+
+- ftpserver.pl: Expanded the SMTP RCPT handler to validate TO addresses
+
+ RCPT_smtp() will now check for a correctly formatted TO address which
+ allows for invalid recipient addresses to be added.
+
+- ftpserver.pl: Added cURL SMTP server detection to HELO command handler
+
+ As curl will send a HELO command after an negative EHLO response, added
+ the same detection from commit b07709f7417c3e to the HELO handler to
+ ensure the test server is identified correctly and an upload isn't
+ performed.
+
+- ftpserver.pl: Corrected response code for successful RCPT command
+
+- ftpserver.pl: Moved invalid RCPT TO: address detection to RCPT handler
+
+ Rather than detecting the TO address as missing in the DATA handler,
+ moved the detection to the RCPT command handler where an error response
+ can be generated.
+
+- RELEASE-NOTES: Corrected missed addition
+
+ Somehow commit 60a20461629fda missed the last item in the sync list
+ even though I'm sure I added it during editing.
+
+- RELEASE-NOTES: Synced with 6dd8bd8d2f9729
+
+- curl.1: Added information about optional login options to --user in manpage
+
+ Added missing information, from curl 7.31.0, regarding the use of the
+ optional login options that may be specified as part of --user.
+
+ For example:
+
+ --user 'user:password;auth=NTLM' in IMAP, POP3 and SMTP protocols.
+
+- ftpserver.pl: Moved cURL SMTP server detection into EHLO command handler
+
+ Moved the special SMTP server detection code from the DATA command
+ handler, which happens further down the operation chain after EHLO,
+ MAIL and RCPT commands, to the EHLO command as it is the first command
+ to be generated by a SMTP operation as well as containing the special
+ "verifiedserver" string from the URL.
+
+ This not only makes it easier and quicker to detect but also means that
+ cURL doesn't need to specify "verifiedserver" as --mail-from and
+ --mail-rcpt arguments.
+
+ More importantly, this also makes the upcoming verification changes to
+ the RCPT handler easier to implement.
+
+Daniel Stenberg (21 Sep 2013)
+- openssl: use correct port number in error message
+
+ In ossl_connect_step2() when the "Unknown SSL protocol error" occurs, it
+ would output the local port number instead of the remote one which
+ showed when doing SSL over a proxy (but with the correct remote host
+ name). As libcurl only speaks SSL to the remote we know it is the remote
+ port.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1281
+ Reported-by: Gordon Marler
+
+- test1415: adjusted to work for 32bit time_t
+
+ The libcurl date parser returns INT_MAX for all dates > 2037 so this
+ test is now made to use 2037 instead of 2038 to work the same for both
+ 32bit and 64bit time_t systems.
+
+Steve Holme (21 Sep 2013)
+- tests: Reworked existing SMTP tests to be single recipient based
+
+ ...in preparation of upcoming multiple recipient tests.
+
+- ftpserver.pl: Corrected SMTP QUIT response to be more realistic
+
+Daniel Stenberg (20 Sep 2013)
+- curl_easy_setopt.3: clarify that TIMEOUT and TIMEOUT_MS set the same value
+
+- [Kim Vandry brought this change]
+
+ Documented --dns-* options in curl manpage
+
+Steve Holme (20 Sep 2013)
+- pop3: Added basic SASL XOAUTH2 support
+
+ Added the ability to use an XOAUTH2 bearer token [RFC6750] with POP3 for
+ authentication using RFC6749 "OAuth 2.0 Authorization Framework".
+
+ The bearer token is expected to be valid for the user specified in
+ conn->user. If CURLOPT_XOAUTH2_BEARER is defined and the connection has
+ an advertised auth mechanism of "XOAUTH2", the user and access token are
+ formatted as a base64 encoded string and sent to the server as
+ "AUTH XOAUTH2 <bearer token>".
+
+- curl: Added clarification to the --mail options in the --help output
+
+ ... that these options apply to SMTP only.
+
+- ftpserver.pl: Moved SMTP RCPT response text into command handler
+
+- tests: Added SMTP invalid --mail-from test
+
+Nick Zitzmann (19 Sep 2013)
+- darwinssl: enable BEAST workaround on iOS 7 & later
+
+ iOS 7 finally added the option to enable 1/n-1 when using TLS 1.0
+ and a CBC cipher, so we now always turn that on unless the user
+ manually turns it off using CURLSSLOPT_ALLOW_BEAST.
+
+ It appears Apple also added some new PSK ciphers, but no interface to
+ use them yet, so we at least support printing them if we find them.
+
+Steve Holme (19 Sep 2013)
+- tests: Updated SMTP AUTH tests to use the new AUTH directive
+
+ ...rather than specify a customised EHLO response.
+
+- tests: Corrected test913 as the QUIT response is received
+
+- tests: Added SMTP large message SIZE test
+
+- ftpserver.pl: Updated email regex from commit 98f7ca7e971006
+
+ ...to not be as strict as it was rejecting valid numeric email
+ addresses.
+
+- tests: Fixed smtp mail from addresses
+
+- ftpserver.pl: Standardised CAPA and AUTH responses
+
+- ftpserver.pl: Corrected POP3 QUIT reply to be more realistic
+
+- runtests.pl: Fixed syntax error in commit c873375123343e
+
+ Possible unintended interpolation in string at line 796
+
+- runtests.pl: Fixed smtp mail from address
+
+ Following changes to ftpserver.pl fixed the mail from address to be a
+ correctly formatted address otherwise the server response will be 501
+ Invalid address.
+
+- ftpserver.pl: Fixed syntax error in commit 98f7ca7e971006
+
+ Can't modify constant item in scalar assignment line 779, near "0;"
+
+- ftpserver.pl: Expanded the SMTP MAIL handler to validate messages
+
+ MAIl_smtp() will now check for a correctly formatted FROM address as
+ well as the optional SIZE parameter comparing it against the server
+ capability when specified.
+
+Daniel Stenberg (17 Sep 2013)
+- [YAMADA Yasuharu brought this change]
+
+ cookies: add expiration
+
+ Implement: Expired Cookies These following situation, curl removes
+ cookie(s) from struct CookieInfo if the cookie expired.
+ - Curl_cookie_add()
+ - Curl_cookie_getlist()
+ - cookie_output()
+
+Steve Holme (17 Sep 2013)
+- ftpserver.pl: Corrected response code for successful MAIL command
+
+- ftpserver.pl: Moved SMTP MAIL handler into own function
+
+- dns: fix compilation with MinGW from commit df69440d05f113
+
+ Avoid 'interface' literal that some MinGW versions define as a macro
+
+ Additionally, corrected some very, very minor coding style errors.
+
+- tests: Fixed test 1406 following recent changes in ftpserver.pl
+
+ By default the mail server doesn't send the SIZE capability but instead
+ it has to be specified as a supported capability.
+
+- tests: Added test for SMTP SIZE capability
+
+- ftpserver.pl: Added the ability to include spaces in capabilities
+
+ For example:
+
+ CAPA "SIZE 1048576" 8BITMIME BINARYMIME
+
+ will populate the capabilities list with the following in:
+
+ SIZE 1048576
+ 8BITMIME
+ BINARYMIME
+
+- ftpserver.pl: Corrected response code for successful SMTP QUIT command
+
+- ftpserver.pl: Fixed syntax error in commit 33c1f2876b9029
+
+ Can't modify constant item in postincrement line 727, near "i++"
+
+- ftpserver.pl: Added CAPA & AUTH directive support to the SMTP EHLO handler
+
+- ftpserver.pl: Fixed SMTP QUIT handler from dadc495540946e
+
+- ftpserver.pl: Moved SMTP EHLO and QUIT handlers in own functions
+
+- ftpserver.pl: Added support for SMTP HELO command
+
+ ...and updated test902 as explicit HELO response is no longer required.
+
+- ftpserver.pl: Added mailbox check to IMAP SELECT handler
+
+- ftpserver.pl: Corrected invalid user details check
+
+ ...in both the IMAP LOGIN and POP3 PASS handlers introduced in commit
+ 187ac693744949 and 84ad1569e5fc93 respectively.
+
+- ftpserver.pl: Moved IMAP LOGIN handler into own function
+
+- ftpserver.pl: Moved POP3 USER and PASS handlers into own functions
+
+- ftpserver.pl: Corrected invalid argument check in POP3 TOP handler
+
+ ...which was accidentally introduced in commit 4d6ef6297ae9b6.
+
+- ftpserver.pl: Added capability prerequisite for extended POP3 commands
+
+- tests: Updated descriptions to be more meaningful
+
+- ftpserver.pl: Added support for IMAP NOOP command
+
+- imap: Fixed response check for NOOP command
+
+- tests: Updated descriptions to be more meaningful
+
+Daniel Stenberg (13 Sep 2013)
+- curl.1: detail how short/long options work
+
+ URL: http://curl.haxx.se/bug/view.cgi?id=1279
+ Suggested-by: Jerry Krinock
+
+Steve Holme (13 Sep 2013)
+- curl: Fixed usage of DNS options when not using c-ares resolver
+
+ Commit 32352ed6adddcb introduced various DNS options, however, these
+ would cause curl to exit with CURLE_NOT_BUILT_IN when c-ares wasn't
+ being used as the backend resolver even if the options weren't set
+ by the user.
+
+ Additionally corrected some minor coding style errors from the same
+ commit.
+
+Daniel Stenberg (13 Sep 2013)
+- curl_easy_setopt.3: mention RTMP URL quirks
+
+ URL: http://curl.haxx.se/bug/view.cgi?id=1278
+ Reported-by: Gorilla Maguila
+
+- [Ben Greear brought this change]
+
+ curl: Add support for various DNS binding options.
+
+ (Passed on to c-ares.)
+
+ Allows something like this:
+
+ curl --dns-interface sta8 --dns-ipv4-addr 8.8.1.111 --interface sta8 \
+ --localaddr 8.8.1.111 --dns-servers 8.8.8.1 www.google.com
+
+ Signed-off-by: Ben Greear <greearb@candelatech.com>
+
+- [Kim Vandry brought this change]
+
+ libcurl: New options to bind DNS to local interfaces or IP addresses
+
+- libcurl.3: for multi interface connections are held in the multi handle
+
+ ... and a few more cleanups/clarifications
+
+Steve Holme (12 Sep 2013)
+- ftpserver.pl: Fixed missing comma from 7fd84b14d219b1
+
+- ftpserver.pl: Fixed variable error introduced in 7fd84b14d219b1
+
+ Global symbol "$mailbox" requires explicit package name
+
+- ftpserver.pl: Added support for UID command
+
+- ftpserver.pl: Added support for LSUB command
+
+- imap: Fixed response check for LSUB and UID commands
+
+- ftpserver.pl: Added support for IMAP COPY command
+
+- ftpserver.pl: Added support for IMAP CLOSE and EXPUNGE commands
+
+- ftpserver.pl: Added support for POP3 RSET command
+
+- ftpserver.pl: Added the ability to remember what messages are deleted
+
+ ...as this will be required for IMAP CLOSE and EXPUNGE commands as well
+ as the POP3 RSET command.
+
+Daniel Stenberg (10 Sep 2013)
+- NI_MAXSERV: remove all use of it
+
+ Solaris with the SunStudio Compiler is reportedly missing this define,
+ but as we're using it without any good reason on all the places it was
+ used I've now instead switched to just use sensible buffer sizes that
+ fit a 32 bit decimal number. Which also happens to be smaller than the
+ common NI_MAXSERV value which is 32 on most machines.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1277
+ Reported-by: D.Flinkmann
+
+- http2: use the support HTTP2 draft version in the upgrade header
+
+ ... instead of HTTP/2.0 to work fine with the nghttpx proxy/server.
+
+Steve Holme (10 Sep 2013)
+- ldap.c: Fix compilation warning
+
+ warning: comparison between signed and unsigned integer expressions
+
+- [Jiri Hruska brought this change]
+
+ imap/pop3/smtp: Speed up SSL connection initialization
+
+ Don't wait for the next callback call (usually 1 second) before
+ continuing with protocol specific connection initialization.
+
+- ldap.c: Corrected build error from commit 857f999353f333
+
+- RELEASE-NOTES: Corrected duplicate in bfefe2400a16b8
+
+- RELEASE-NOTES: Corrected typo from bfefe2400a16b8
+
+- RELEASE-NOTES: synced with 25c68903756d6b
+
+Daniel Stenberg (10 Sep 2013)
+- README.http2: explain nghttp2 a little
+
+Steve Holme (9 Sep 2013)
+- tests: Added test for POP3 TOP command
+
+- ftpserver.pl: Added support for POP3 TOP command
+
+- tests: Added test for POP3 UIDL command
+
+- ftpserver.pl: Added support for POP3 UIDL command
+
+Daniel Stenberg (9 Sep 2013)
+- http2: adjust to new nghttp2_pack_settings_payload proto
+
+ This function was modified in nghttp2 git commit a1c3f89c72e51
+
+Kamil Dudka (9 Sep 2013)
+- url: handle abortion by read/write callbacks, too
+
+ Otherwise, the FTP protocol would unnecessarily hang 60 seconds if
+ aborted in the CURLOPT_HEADERFUNCTION callback.
+
+ Reported by: Tomas Mlcoch
+ Bug: https://bugzilla.redhat.com/1005686
+
+Daniel Stenberg (9 Sep 2013)
+- ldap: fix the build for systems with ldap_url_parse()
+
+ Make sure that the custom struct fields are only used by code that
+ doesn't use a struct defintion from the outside.
+
+ Attempts to fix the problem introduced in 3dc6fc42bfc61b
+
+Steve Holme (9 Sep 2013)
+- [Jiri Hruska brought this change]
+
+ pingpong: Check SSL library buffers for already read data
+
+ Otherwise the connection can get stuck during various phases, waiting
+ for new data on the socket using select() etc., but it will never be
+ received as the data has already been read into SSL library.
+
+- imap: Fixed calculation of transfer when partial FETCH received
+
+ The transfer size would be calculated incorrectly if the email contained
+ within the FETCH response, had been partially received by the pingpong
+ layer. As such the following, example output, would be seen if the
+ amount remaining was smaller than the amount received:
+
+ * Excess found in a non pipelined read: excess = 1394, size = 262,
+ maxdownload = 262, bytecount = 1374
+ * transfer closed with -1112 bytes remaining to read
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0170.html
+ Reported-by: John Dunn
+
+- ftpserver.pl: Fixed empty array checks
+
+ ...from commits 28427b408326a1 and e8313697b6554b.
+
+- ftpserver: Reworked AUTH support to allow for specifying the mechanisms
+
+ Renamed SUPPORTAUTH to AUTH and added support for specifying a list of
+ supported SASL mechanisms to return to the client.
+
+ Additionally added the directive to the FILEFORMAT document.
+
+- ftpserver: Reworked CAPA support to allow for specifying the capabilities
+
+ Renamed SUPPORTCAPA to CAPA and added support for specifying a list of
+ supported capabilities to return to the client.
+
+ Additionally added the directive to the FILEFORMAT document.
+
+- ftpserver.pl: Corrected POP3 LIST as message numbers should be contiguous
+
+ The message numbers given in the LIST response are an index into the
+ list, which are only valid for the current session, rather than being a
+ unique message identifier. An index would only be missing from the LIST
+ response if a DELE command had been issued within the same session and
+ had not been committed by the end of session QUIT command. Once
+ committed the POP3 server will regenerate the message numbers in the
+ next session to be contiguous again. As such our LIST response should
+ list message numbers contiguously until we support a DELE command in the
+ same session.
+
+ Should a POP3 user require the unique message ID for any or all
+ messages then they should use the extended UIDL command. This command
+ will be supported by the test ftpserver in an upcoming commit.
+
+Daniel Stenberg (8 Sep 2013)
+- [Clemens Gruber brought this change]
+
+ curl_easy_pause: suggest one way to unpause
+
+Steve Holme (8 Sep 2013)
+- tests: Updated descriptions to be more meaningful
+
+- tests: Added test for POP3 NOOP command
+
+- ftpserver.pl: Added support for POP3 NOOP command
+
+- ftpserver.pl: Fixed 'Use of uninitialized value $args in string ne'
+
+- tests: Added test for POP3 STAT command
+
+- ftpserver.pl: Added support for POP STAT command
+
+- ftpserver.pl: Moved POP3 QUIT handler into own function
+
+- ftpserver.pl: Reordered the POP3 handlers to be alphabetical
+
+ In preparation for additional POP3 tests, re-ordered the command
+ function defintions to be sorted alphabetically.
+
+- ftpserver.pl: Corrected misaligned indentation in POP3 handlers
+
+ Fixed incorrect indentation used in both the RETR_pop3 and LIST_pop3
+ functions which was 5 and 9 characters rather than 4 and 8.
+
+- tests: Added test for POP3 DELE command
+
+unknown (7 Sep 2013)
+- [Steve Holme brought this change]
+
+ ftpserver.pl: Added support for POP3 DELE command
+
+Daniel Stenberg (7 Sep 2013)
+- http2: include curl_memory.h
+
+ Detected by test 1132
+
+Nick Zitzmann (7 Sep 2013)
+- http: fix build warning under LLVM
+
+ When building the code using LLVM Clang without NGHTTP2, I was getting
+ this warning:
+ ../lib/http.h:155:1: warning: empty struct is a GNU extension [-Wgnu]
+ Placing a dummy variable into the data structure silenced the warning.
+
+Daniel Stenberg (7 Sep 2013)
+- http2: actually init nghttp2 and send HTTP2-Settings properly
+
+- README.http2: how to use it best with the multi API?
+
+- http2: first embryo toward Upgrade:
+
+- http: rename use_http_1_1 to use_http_1_1plus
+
+ Since it now actually says if 1.1 or a later version should be used.
+
+- configure: improve CURL_CHECK_COMPILER_PROTOTYPE_MISMATCH
+
+ The compiler test used a variable before it was assigned when it tried
+ to see how it acts on a mismatching prototype, which could cause a false
+ positive.
+
+- [Petr Písař brought this change]
+
+ Pass password to OpenSSL engine by user interface
+
+ Recent OpenSSL uses user interface abstraction to negotiate access to
+ private keys in the cryprographical engines. An OpenSSL application is
+ expected to implement the user interface. Otherwise a default one
+ provided by OpenSSL (interactive standard I/O) will be used and the
+ aplication will have no way how to pass a password to the engine.
+
+ Longer-desc: http://curl.haxx.se/mail/lib-2013-08/0265.html
+
+- urlglob: improved error messages and column number on bad use
+
+ Introduce a convenience macro and keep of the column better so that it
+ can point out the offending column better.
+
+ Updated test 75 accordingly.
+
+- urlglob: avoid error code translation
+
+ By using the correct values from the start we don't have to translate
+ them!
+
+- urlglob: avoid NULL pointer dereference
+
+ Thanks to clang-analyzer
+
+- [Gisle Vanem brought this change]
+
+ http2: use correct include for snprintf
+
+ Using the first little merge of nghttp2 into libcurl, I stumbeled on the
+ missing 'snprintf' in MSVCRT. Isn't this how we do it for other libcurl
+ files? I.e. use 'curl_msnprintf' and not 'snprintf' directly:
+
+- --data: mention CRLF treatment when reading from file
+
+- [Geoff Beier brought this change]
+
+ LDAP: fix bad free() when URL parsing failed
+
+ When an error occurs parsing an LDAP URL, The ludp->lud_attrs[i] entries
+ could be freed even though they sometimes point to data within an
+ allocated area.
+
+ This change introduces a lud_attrs_dup[] array for the duplicated string
+ pointers, and it removes the unused lud_exts array.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0209.html
+
+Nick Zitzmann (5 Sep 2013)
+- darwinssl: add support for PKCS#12 files for client authentication
+
+ I also documented the fact that the OpenSSL engine also supports them.
+
+Daniel Stenberg (5 Sep 2013)
+- symbols: added HTTP2 symbols and sorted list
+
+ CURL_HTTP_VERSION_2_0 and CURL_VERSION_HTTP2 are new
+
+- configure: add HTTP2 as a curl-config --feature output
+
+ Fixes the test 1014 failure
+
+- curl: unbreak --http1.0 again
+
+ I broke it in 2eabb7d590
+
+- SASL: fix compiler warnings
+
+ comparison between signed and unsigned integer expressions
+
+ suggest parentheses around '&&' within '||' (twice)
+
+- curl: add --http1.1 and --http2.0 options
+
+- Curl_setopt: refuse CURL_HTTP_VERSION_2_0 if built without support
+
+- http2: add http2.[ch] and add nghttp2 version output
+
+- curl -V: output HTTP2 as a feature if present
+
+- curl.h: add CURL_VERSION_HTTP2 as a feature
+
+ It isn't added as a separate protocol as HTTP2 will be done over HTTP://
+ URLs that can be upgraded to HTTP2 if the server supports it as well.
+
+Steve Holme (4 Sep 2013)
+- imap/smtp: Fixed incorrect SASL mechanism selection with XOAUTH2 servers
+
+ XOAUTH2 would be selected in preference to LOGIN and PLAIN if the IMAP
+ or SMTP server advertised support for it even though a user's password
+ was supplied but bearer token wasn't.
+
+ Modified the selection logic so that XOAUTH2 will only be selected if
+ the server supports it and A) The curl user/libcurl programmer has
+ specifically asked for XOAUTH via the ;AUTH=XOAUTH login option or 2)
+ The bearer token is specified. Obviously if XOAUTH is asked for via
+ the login option but no token is specified the user will receive a
+ authentication failure which makes more sense than no known
+ authentication mechanisms supported!
+
+Daniel Stenberg (4 Sep 2013)
+- curl.h: added CURL_HTTP_VERSION_2_0
+
+ Initial library considerations documented in lib/README.http2
+
+- configure: added --with-nghttp2
+
+- acinclude: fix --without-ca-path when cross-compiling
+
+ The commit 7b074a460b64811 to CURL_CHECK_CA_BUNDLE in 7.31 (don't check
+ for paths when cross-compiling) causes --without-ca-path to no longer
+ works when cross-compiling, since ca and capath only ever get set to
+ "no" when not cross-compiling, I attach a patch that works for me. Also
+ in the cross-compilation case, no ca-path seems to be a better default
+ (IMVHO) than empty ca-path.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1273
+ Patch-by: Stefan Neis
+
+Steve Holme (2 Sep 2013)
+- lib1512.c: Fixed compilation warning
+
+ An enumerated type is mixed with another type.
+
+ ...as well as a small coding style error.
+
+Guenter Knauf (1 Sep 2013)
+- Killed warning 'res' might be used uninitialized.
+
+Steve Holme (1 Sep 2013)
+- url.c: Fixed compilation warning
+
+ An enumerated type is mixed with another type
+
+- easy.c: Fixed compilation warning
+
+ warning: `code' might be used uninitialized in this function
+
+Daniel Stenberg (31 Aug 2013)
+- -x: rephrased the --proxy section somewhat
+
+Steve Holme (31 Aug 2013)
+- tests: Added test for IMAP CHECK command
+
+- ftpserver.pl: Added support for the IMAP CHECK command
+
+Guenter Knauf (31 Aug 2013)
+- Removed reference to krb4.c.
+
+Steve Holme (31 Aug 2013)
+- ftpserver.pl: Corrected flawed logic in commit 1ca6ed7b75cad0
+
+- imap: Fixed response check for EXPUNGE command
+
+- ftpserver.pl: Added argument check to IMAP command handlers
+
+ Added BAD argument check to the following IMAP command handlers:
+
+ APPEND, STORE, LIST, EXAMINE, STATUS and SEARCH
+
+- ftpserver.pl: More whitespace corrections
+
+ LIST_imap() had a second level of indentation at 9 characters and not 8.
+
+- ftpserver.pl: Small correction tidy up
+
+ Corrected some IMAP variable names and whitespace issues.
+
+- [Kyle L. Huff brought this change]
+
+ docs: Added documentation for CURLOPT_BEARER
+
+- [Kyle L. Huff brought this change]
+
+ curl.1: Add usage of '--bearer' option
+
+- tests: Added tests for IMAP CREATE, DELETE and RENAME commands
+
+Daniel Stenberg (30 Aug 2013)
+- ftpserver: Bareword "to_mailbox" not allowed
+
+ Added missing $
+
+Steve Holme (30 Aug 2013)
+- ftpserver.pl: Added support for IMAP CREATE, DELETE and RENAME commands
+
+Daniel Stenberg (29 Aug 2013)
+- FTP: fix getsock during DO_MORE state
+
+ ... when doing upload it would return the wrong values at times. This
+ commit attempts to cleanup the mess.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0109.html
+ Reported-by: Mike Mio
+
+- curl_multi_remove_handle: allow multiple removes
+
+ When removing an already removed handle, avoid that to ruin the
+ internals and just return OK instead.
+
+Steve Holme (29 Aug 2013)
+- ftpserver.pl: Updated IMAP EXAMINE handler to use dynamic test data
+
+Daniel Stenberg (29 Aug 2013)
+- unit1304: include memdebug and free everything correctly
+
+- Curl_parsenetrc: document that the arguments must be allocated
+
+- easy: rename struct monitor to socketmonitor
+
+ 'struct monitor', introduced in 6cf8413e, already exists in an IRIX
+ header file (sys/mon.h) which gets included via various standard headers
+ by lib/easy.c
+
+ cc-1101 cc: ERROR File = ../../curl/lib/easy.c, Line = 458
+ "monitor" has already been declared in the current scope.
+
+ Reported-by: Tor Arntsen
+
+Steve Holme (29 Aug 2013)
+- ftpserver.pl: Added SELECT check to IMAP FETCH and STORE handlers
+
+- ftpserver.pl: Corrected accidental move of logmsg() call
+
+ Corrected the call to logmsg() in the IMAP SEARCH handler from commit
+ 4ae7b7ea691497 as it should have been outputting the what argument and
+ not the test number.
+
+Daniel Stenberg (28 Aug 2013)
+- ftpserver: add missing '}' from 4ae7b7ea69149
+
+Steve Holme (28 Aug 2013)
+- ftpserver.pl: Added SELECT check to IMAP SEARCH command
+
+- ftpserver.pl: Fixed IMAP SEARCH command
+
+Daniel Stenberg (28 Aug 2013)
+- bump: next release is 7.33.0 due to added features
+
+- symbols-in-versions: add CURLOPT_XOAUTH2_BEARER
+
+Steve Holme (28 Aug 2013)
+- tests: Added test for IMAP SEARCH command
+
+Daniel Stenberg (28 Aug 2013)
+- valgrind.supp: fix for regular curl_easy_perform too
+
+ When we introduced curl_easy_perform_ev, this got a slightly modified
+ call trace. Without this, test 165 causes a false positive valgrind
+ error.
+
+- valgrind.supp: add the event-based call stack-trace too
+
+ Without this, test 165 triggers a valgrind error when ran with
+ curl_easy_perform_ev
+
+- multi_socket: improved 100-continue timeout handling
+
+ When waiting for a 100-continue response from the server, the
+ Curl_readwrite() will refuse to run if called until the timeout has been
+ reached.
+
+ We timeout code in multi_socket() allows code to run slightly before the
+ actual timeout time, so for test 154 it could lead to the function being
+ executed but refused in Curl_readwrite() and then the application would
+ just sit idling forever.
+
+ This was detected with runtests.pl -e on test 154.
+
+Steve Holme (27 Aug 2013)
+- ftpserver.pl: Added support for IMAP SEARCH command
+
+- tool_operate.c: Fixed compilation warning
+
+ warning: implicit declaration of function 'checkpasswd'
+
+- curl: Moved check for password out of get parameter loop
+
+ Moved the calls to checkpasswd() out of the getparameter() function
+ which allows for any related arguments to be specified on the command
+ line before or after --user (and --proxy-user).
+
+ For example: --bearer doesn't need to be specified before --user to
+ prevent curl from asking for an unnecessary password as is the case
+ with commit e7dcc454c67a2f.
+
+- RELEASE-NOTES: synced with acf59be7f09a7
+
+- [Kyle L. Huff brought this change]
+
+ curl: added --bearer option to help
+
+ Added the --bearer option to the help output
+
+- [Kyle L. Huff brought this change]
+
+ curl: added basic SASL XOAUTH2 support
+
+ Added the ability to specify an XOAUTH2 bearer token [RFC6750] via the
+ --bearer option.
+
+ Example usage:
+ curl --url "imaps://imap.gmail.com:993/INBOX/;UID=1" --ssl-reqd
+ --bearer ya29.AHES6Z...OMfsHYI --user username@example.com
+
+- tool_urlglob.c: Fixed compiler warnings
+
+ warning: 'variable' may be used uninitialized in this function
+
+Daniel Stenberg (26 Aug 2013)
+- security.h: rename to curl_sec.h to avoid name collision
+
+ I brought back security.h in commit bb5529331334e. As we actually
+ already found out back in 2005 in commit 62970da675249, the file name
+ security.h causes problems so I renamed it curl_sec.h instead.
+
+- runtests.pl: allow -vc point to a separate curl binary to verify with
+
+ The specified curl binary will then be used to verify the running
+ server(s) instead of the development version. This is very useful in
+ some cases when the development version fails to verify correctly as
+ then the test case may not run at all.
+
+ The actual test will still be run with the "normal" curl executable
+ (unless the test case specifies something differently).
+
+Steve Holme (26 Aug 2013)
+- [Kyle L. Huff brought this change]
+
+ smtp: added basic SASL XOAUTH2 support
+
+ Added the ability to use an XOAUTH2 bearer token [RFC6750] with SMTP for
+ authentication using RFC6749 "OAuth 2.0 Authorization Framework".
+
+ The bearer token is expected to be valid for the user specified in
+ conn->user. If CURLOPT_XOAUTH2_BEARER is defined and the connection has
+ an advertised auth mechanism of "XOAUTH2", the user and access token are
+ formatted as a base64 encoded string and sent to the server as
+ "AUTH XOAUTH2 <bearer token>".
+
+- [Kyle L. Huff brought this change]
+
+ imap: added basic SASL XOAUTH2 support
+
+ Added the ability to use an XOAUTH2 bearer token [RFC6750] with IMAP for
+ authentication using RFC6749 "OAuth 2.0 Authorization Framework".
+
+ The bearer token is expected to be valid for the user specified in
+ conn->user. If CURLOPT_XOAUTH2_BEARER is defined and the connection has
+ an advertised auth mechanism of "XOAUTH2", the user and access token are
+ formatted as a base64 encoded string and sent to the server as
+ "A001 AUTHENTICATE XOAUTH2 <bearer token>".
+
+- security.h: Fixed compilation warning
+
+ ISO C forbids forward references to 'enum' types
+
+Daniel Stenberg (26 Aug 2013)
+- KNOWN_BUGS: refer to bug numbers with the existing number series
+
+ The old numbers would still redirect but who knows for how long...
+
+Steve Holme (25 Aug 2013)
+- [Kyle L. Huff brought this change]
+
+ options: added basic SASL XOAUTH2 support
+
+ Added the ability to specify an XOAUTH2 bearer token [RFC6750] via the
+ option CURLOPT_XOAUTH2_BEARER for authentication using RFC6749 "OAuth
+ 2.0 Authorization Framework".
+
+- [Kyle L. Huff brought this change]
+
+ sasl: added basic SASL XOAUTH2 support
+
+ Added the ability to generated a base64 encoded XOAUTH2 token
+ containing: "user=<username>^Aauth=Bearer <bearer token>^A^A"
+ as per RFC6749 "OAuth 2.0 Authorization Framework".
+
+Daniel Stenberg (25 Aug 2013)
+- FTP: remove krb4 support
+
+ We've announced this pending removal for a long time and we've
+ repeatedly asked if anyone would care or if anyone objects. Nobody has
+ objected. It has probably not even been working for a good while since
+ nobody has tested/used this code recently.
+
+ The stuff in krb4.h that was generic enough to be used by other sources
+ is now present in security.h
+
+- easy: define away easy_events() for non-debug builds
+
+- FAQ: editorial updates
+
+ Several language fixes. Several reformats that should make the HTML
+ generation of this document look better.
+
+ Reported-by: Dave Thompson
+
+- RELEASE-NOTES: synced with 22adb46a32bee
+
+- multi: move on from STATE_DONE faster
+
+ Make sure we always return CURLM_CALL_MULTI_PERFORM when we reach
+ CURLM_STATE_DONE since the state is transient and it can very well
+ continue executing as there is nothing to wait for.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0211.html
+ Reported-by: Yi Huang
+
+- curl.h: name space pollution by "enum type"
+
+ Renamed to "enum curl_khtype" now. Will break compilation for programs
+ that rely on the enum name.
+
+ Bug: https://github.com/bagder/curl/pull/76
+ Reported-by: Shawn Landden
+
+- TFTP: make the CURLOPT_LOW_SPEED* options work
+
+ ... this also makes sure that the progess callback gets called more
+ often during TFTP transfers.
+
+ Added test 1238 to verify.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1269
+ Reported-by: Jo3
+
+- tftpd: support "writedelay" within <servercmd>
+
+- tftpd: convert 6 global variables into local ones
+
+- [Gisle Vanem brought this change]
+
+ curl_easy_perform_ev: make it CURL_EXTERN
+
+ I build curl.exe (using MingW) with '-DCURLDEBUG' and by importing from
+ libcurl.dll. Which means the new curl_easy_perform_ev() must be
+ exported from libcurl.dll.
+
+- CURLM_ADDED_ALREADY: new error code
+
+ Doing curl_multi_add_handle() on an easy handle that is already added to
+ a multi handle now returns this error code. It previously returned
+ CURLM_BAD_EASY_HANDLE for this condition.
+
+- multi_init: moved init code here from add_handle
+
+ The closure_handle is "owned" by the multi handle and it is
+ unconditional so the setting up of it should be in the Curl_multi_handle
+ function rather than curl_multi_add_handle.
+
+- multi: remove dns cache creation code from *add_handle
+
+ As it is done unconditionally in multi_init() this code will never run!
+
+- curl_easy_perform_ev: debug/test function
+
+ This function is meant to work *exactly* as curl_easy_perform() but will
+ use the event-based libcurl API internally instead of
+ curl_multi_perform(). To avoid relying on an actual event-based library
+ and to not use non-portable functions (like epoll or similar), there's a
+ rather inefficient emulation layer implemented on top of Curl_poll()
+ instead.
+
+ There's currently some convenience logging done in curl_easy_perform_ev
+ which helps when tracking down problems. They may be suitable to remove
+ or change once things seem to be fine enough.
+
+ curl has a new --test-event option when built with debug enabled that
+ then uses curl_easy_perform_ev() instead of curl_easy_perform(). If
+ built without debug, using --test-event will only output a warning
+ message.
+
+ NOTE: curl_easy_perform_ev() is not part if the public API on purpose.
+ It is only present in debug builds of libcurl and MUST NOT be considered
+ stable even then. Use it for libcurl-testing purposes only.
+
+ runtests.pl now features an -e command line option that makes it use
+ --test-event for all curl command line tests. The man page is updated.
+
+- [Gisle Vanem brought this change]
+
+ transfer: the recent sessionhandle change broke CURL_DOES_CONVERSIONS
+
+- test1237: verify 1000+ letter user name + passwords
+
+- [Jonathan Nieder brought this change]
+
+ url: handle arbitrary-length username and password before '@'
+
+ libcurl quietly truncates usernames, passwords, and options from
+ before an '@' sign in a URL to 255 (= MAX_CURL_PASSWORD_LENGTH - 1)
+ characters to fit in fixed-size buffers on the stack. Allocate a
+ buffer large enough to fit the parsed fields on the fly instead to
+ support longer passwords.
+
+ After this change, there are no more uses of MAX_CURL_OPTIONS_LENGTH
+ left, so stop defining that constant while at it. The hardcoded max
+ username and password length constants, on the other hand, are still
+ used in HTTP proxy credential handling (which this patch doesn't
+ touch).
+
+ Reported-by: Colby Ranger
+
+- [Jonathan Nieder brought this change]
+
+ url: handle exceptional cases first in parse_url_login()
+
+ Instead of nesting "if(success)" blocks and leaving the reader in
+ suspense about what happens in the !success case, deal with failure
+ cases early, usually with a simple goto to clean up and return from
+ the function.
+
+ No functional change intended. The main effect is to decrease the
+ indentation of this function slightly.
+
+- [Jonathan Nieder brought this change]
+
+ Curl_setopt: handle arbitrary-length username and password
+
+ libcurl truncates usernames, passwords, and options set with
+ curl_easy_setopt to 255 (= MAX_CURL_PASSWORD_LENGTH - 1) characters.
+ This doesn't affect the return value from curl_easy_setopt(), so from
+ the caller's point of view, there is no sign anything strange has
+ happened, except that authentication fails.
+
+ For example:
+
+ # Prepare a long (300-char) password.
+ s=0123456789; s=$s$s$s$s$s$s$s$s$s$s; s=$s$s$s;
+ # Start a server.
+ nc -l -p 8888 | tee out & pid=$!
+ # Tell curl to pass the password to the server.
+ curl --user me:$s http://localhost:8888 & sleep 1; kill $pid
+ # Extract the password.
+ userpass=$(
+ awk '/Authorization: Basic/ {print $3}' <out |
+ tr -d '\r' |
+ base64 -d
+ )
+ password=${userpass#me:}
+ echo ${#password}
+
+ Expected result: 300
+ Actual result: 255
+
+ The fix is simple: allocate appropriately sized buffers on the heap
+ instead of trying to squeeze the provided values into fixed-size
+ on-stack buffers.
+
+ Bug: http://bugs.debian.org/719856
+ Reported-by: Colby Ranger
+
+- [Jonathan Nieder brought this change]
+
+ netrc: handle longer username and password
+
+ libcurl truncates usernames and passwords it reads from .netrc to
+ LOGINSIZE and PASSWORDSIZE (64) characters without any indication to
+ the user, to ensure the values returned from Curl_parsenetrc fit in a
+ caller-provided buffer.
+
+ Fix the interface by passing back dynamically allocated buffers
+ allocated to fit the user's input. The parser still relies on a
+ 256-character buffer to read each line, though.
+
+ So now you can include an ~246-character password in your .netrc,
+ instead of the previous limit of 63 characters.
+
+ Reported-by: Colby Ranger
+
+- [Jonathan Nieder brought this change]
+
+ url: allocate username, password, and options on the heap
+
+ This makes it possible to increase the size of the buffers when needed
+ in later patches. No functional change yet.
+
+- [Jonathan Nieder brought this change]
+
+ url: use goto in create_conn() for exception handling
+
+ Instead of remembering before each "return" statement which temporary
+ allocations, if any, need to be freed, take care to set pointers to
+ NULL when no longer needed and use a goto to a common block to exit
+ the function and free all temporaries.
+
+ No functional change intended. Currently the only temporary buffer in
+ this function is "proxy" which is already correctly freed when
+ appropriate, but there will be more soon.
+
+- [Jonathan Nieder brought this change]
+
+ sasl: allow arbitrarily long username and password
+
+ Use appropriately sized buffers on the heap instead of fixed-size
+ buffers on the stack, to allow for longer usernames and passwords.
+
+ Callers never pass anything longer than MAX_CURL_USER_LENGTH (resp.
+ MAX_CURL_PASSWORD_LENGTH), so no functional change inteded yet.
+
+Steve Holme (19 Aug 2013)
+- [Alex McLellan brought this change]
+
+ imap: Fixed response check for SEARCH command
+
+ Adding this line allows libcurl to return the server response when
+ performing a search command via a custom request.
+
+Daniel Stenberg (16 Aug 2013)
+- glob: error out on range overflow
+
+ The new multiply() function detects range value overflows. 32bit
+ machines will overflow on a 32bit boundary while 64bit hosts support
+ ranges up to the full 64 bit range.
+
+ Added test 1236 to verify.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1267
+ Reported-by: Will Dietz
+
+- urlglob: better detect unclosed braces, empty lists and overflows
+
+ A rather big overhaul and cleanup.
+
+ 1 - curl wouldn't properly detect and reject globbing that ended with an
+ open brace if there were brackets or braces before it. Like "{}{" or
+ "[0-1]{"
+
+ 2 - curl wouldn't properly reject empty lists so that "{}{}" would
+ result in curl getting (nil) strings in the output.
+
+ 3 - By using strtoul() instead of sscanf() the code will now detected
+ over and underflows. It now also better parses the step argument to only
+ accept positive numbers and only step counters that is smaller than the
+ delta between the maximum and minimum numbers.
+
+ 4 - By switching to unsigned longs instead of signed ints for the
+ counters, the max values for []-ranges are now very large (on 64bit
+ machines).
+
+ 5 - Bumped the maximum number of globs in a single URL to 100 (from 10)
+
+ 6 - Simplified the code somewhat and now it stores fixed strings as
+ single- entry lists. That's also one of the reasons why I did (5) as now
+ all strings between "globs" will take a slot in the array.
+
+ Added test 1234 and 1235 to verify. Updated test 87.
+
+ This commit fixes three separate bug reports.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1264
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1265
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1266
+ Reported-by: Will Dietz
+
+- [John Malmberg brought this change]
+
+ VMS: Add RELEASE-NOTES to vms document
+
+ Add the curl release notes to the release note document generated for
+ VMS packages.
+
+ Add the different filenames generated by a daily build to the
+ cleanup procedures.
+
+- [Tor Arntsen brought this change]
+
+ tests 2032, 2033: Don't hardcode port in expected output
+
+- ftp: convert state names to a global array
+
+ ... just to make them easier to print in debug ouputs while debugging.
+ They are still within #ifdef [debugbuild].
+
+- --help: fix the --sasl-ir in the help output
+
+- ftp_domore_getsock: when passive mode, the second conn is already there
+
+ This makes the socket callback get called with the proper bitmask as
+ otherwise the application could be left hanging waiting for reading on
+ an upload connection!
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0043.html
+ Reported-by: Bill Doyle
+
+- curl: make --no-[option] work properly for several options
+
+ --create-dirs, --crlf, --socks5-gssapi-nec and --sasl-ir
+
+Kamil Dudka (12 Aug 2013)
+- nss: make sure that NSS is initialized
+
+ ... prior to calling PK11_GenerateRandom()
+
+Daniel Stenberg (12 Aug 2013)
+- multi: s/easy/data
+
+ With everything being struct SessionHandle pointers now, this rename
+ makes multi.c use the library-wide practise of calling that pointer
+ 'data' instead of the previously used 'easy'.
+
+- cleanup: removed one function, made one static
+
+ Moved Curl_easy_addmulti() from easy.c to multi.c, renamed it to
+ easy_addmulti and made it static.
+
+ Removed Curl_easy_initHandleData() and uses of it since it was emptied
+ in commit cdda92ab67b47d74a.
+
+- SessionHandle: the protocol specific pointer is now a void *
+
+ All protocol handler structs are now opaque (void *) in the
+ SessionHandle struct and moved in the request-specific sub-struct
+ 'SingleRequest'. The intension is to keep the protocol specific
+ knowledge in their own dedicated source files [protocol].c etc.
+
+ There's some "leakage" where this policy is violated, to be addressed at
+ a later point in time.
+
+- urldata: clean up the use of the protocol specific structs
+
+ 1 - always allocate the struct in protocol->setup_connection. Some
+ protocol handlers had to get this function added.
+
+ 2 - always free at the end of a request. This is also an attempt to keep
+ less memory in the handle after it is completed.
+
+- version number: bump to 7.32.1 for now
+
+ Start working on the next version and up some counters.
+
+Version 7.32.0 (11 Aug 2013)
+
+Daniel Stenberg (11 Aug 2013)
+- THANKS: added contributors from the 7.32.0 release notes
+
+- [Fabian Keil brought this change]
+
+ test1228: add 'HTTP proxy' to the keywords
+
+- [Fabian Keil brought this change]
+
+ tests: add keywords for a couple of FILE tests
+
+- [Fabian Keil brought this change]
+
+ tests: add 'FAILURE' keywords to tests 1409 and 1410
+
+- [Fabian Keil brought this change]
+
+ tests: add keywords for a couple of HTTP tests
+
+- [Fabian Keil brought this change]
+
+ tests: add keywords for a couple of FTP tests
+
+- [Fabian Keil brought this change]
+
+ test1511: consistently terminate headers with CRLF
+
+- DISABLED: shut of test 1512 for now
+
+ It shows intermittent failures and I haven't been able to track them
+ down yet. Disable this test for now.
+
+- curl_multi_add_handle.3: ... that timer callback is for event-based
+
+- comments: remove old and wrong multi/easy interface statements
+
+- curl_multi_add_handle.3: mention the CURLMOPT_TIMERFUNCTION use
+
+- [John E. Malmberg brought this change]
+
+ KNOWN_BUGS: 22 and 57 have been fixed and committed
+
+- RELEASE-NOTES: synced with d20def20462e7
+
+- global dns cache: fix memory leak
+
+ The take down of the global dns cache didn't take CURLOPT_RESOLVE names
+ into account.
+
+- global dns cache: didn't work [regression]
+
+ CURLOPT_DNS_USE_GLOBAL_CACHE broke in commit c43127414d89ccb (been
+ broken since the libcurl 7.29.0 release). While this option has been
+ documented as deprecated for almost a decade and nobody even reported
+ this bug, it should remain functional.
+
+ Added test case 1512 to verify
+
+Yang Tse (8 Aug 2013)
+- [John Malmberg brought this change]
+
+ packages/vms: update VMS build files
+
+ VMS modified files either missing from a previous commit and changes
+ to remove references to CVS repositories.
+
+Daniel Stenberg (8 Aug 2013)
+- FTP: renamed several local functions
+
+ The previous naming scheme ftp_state_post_XXXX() wasn't really helpful
+ as it wasn't always immediately after 'xxxx' and it wasn't easy to
+ understand what it does based on such a name.
+
+ This new one is instead ftp_state_yyyy() where yyyy describes what it
+ does or sends.
+
+- mk-ca-bundle.1: don't install on make install
+
+ Since the mk-ca-bundle tool itself isn't installed with make install,
+ there's no point in installing its documentation.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-08/0057.html
+ Reported-by: Guenter Knauf
+
+Yang Tse (7 Aug 2013)
+- packages/vms/Makefile.am: add latest file additions to EXTRA_DIST
+
+- [John Malmberg brought this change]
+
+ Building_vms_pcsi_kit
+
+ These are the files needed to build VMS distribution packages known as
+ PCSI kits.
+
+ Also minor update to the existing files, mainly to the documentation and
+ file clean up code.
+
+Daniel Stenberg (6 Aug 2013)
+- LIBCURL-STRUCTS: new document
+
+ This is the first version of this new document, detailing the seven
+ perhaps most important internal structs in libcurl source code:
+
+ 1.1 SessionHandle
+ 1.2 connectdata
+ 1.3 Curl_multi
+ 1.4 Curl_handler
+ 1.5 conncache
+ 1.6 Curl_share
+ 1.7 CookieInfo
+
+- CONTRIBUTE: minor language polish
+
+- FTP: when EPSV gets a 229 but fails to connect, retry with PASV
+
+ This is a regression as this logic used to work. It isn't clear when it
+ broke, but I'm assuming in 7.28.0 when we went all-multi internally.
+
+ This likely never worked with the multi interface. As the failed
+ connection is detected once the multi state has reached DO_MORE, the
+ Curl_do_more() function was now expanded somewhat so that the
+ ftp_do_more() function can request to go "back" to the previous state
+ when it makes another attempt - using PASV.
+
+ Added test case 1233 to verify this fix. It has the little issue that it
+ assumes no service is listening/accepting connections on port 1...
+
+ Reported-by: byte_bucket in the #curl IRC channel
+
+Nick Zitzmann (5 Aug 2013)
+- md5: remove use of CommonCrypto-to-OpenSSL macros for the benefit of Leopard
+
+ For some reason, OS X 10.5's GCC suddenly stopped working correctly with
+ macros that change MD5_Init etc. in the code to CC_MD5_Init etc., so I
+ worked around this by removing use of the macros and inserting static
+ functions that just call CommonCrypto's implementations of the functions
+ instead.
+
+Guenter Knauf (5 Aug 2013)
+- Simplify check for trusted certificates.
+
+ This changes the previous check for untrusted certs to a check for
+ certs explicitely marked as trusted.
+ The change is backward-compatible (tested with certdata.txt v1.80).
+
+Daniel Stenberg (5 Aug 2013)
+- configure: warn on bad env variable use, don't error
+
+ Use XC_CHECK_BUILD_FLAGS instead XC_CHECK_USER_FLAGS.
+
+- Revert "configure: don't error out on variable confusions, just warn"
+
+ This reverts commit 6b27703b5f525eccdc0a8409f51de8595c75132a.
+
+- formadd: wrong pointer for file name when CURLFORM_BUFFERPTR used
+
+ The internal function that's used to detect known file extensions for
+ the default Content-Type got the the wrong pointer passed in when
+ CURLFORM_BUFFER + CURLFORM_BUFFERPTR were used. This had the effect that
+ strlen() would be used which could lead to an out-of-bounds read (and
+ thus segfault). In most cases it would only lead to it not finding or
+ using the correct default content-type.
+
+ It also showed that test 554 and test 587 were testing for the
+ previous/wrong behavior and now they're updated as well.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1262
+ Reported-by: Konstantin Isakov
+
+Guenter Knauf (4 Aug 2013)
+- Skip more untrusted certificates.
+
+ Christian Heimes brought to our attention that the certdata.txt
+ format has recently changed [1], causing ca-bundle.crt created
+ with mk-ca-bundle.[pl|vbs] to include untrusted certs.
+
+ [1] http://lists.debian.org/debian-release/2012/11/msg00411.html
+
+Daniel Stenberg (4 Aug 2013)
+- configure: don't error out on variable confusions, just warn
+
+- configure: rephrase the notice in _XC_CHECK_VAR_*
+
+ Instead of claiming it is an error, we call it a "note" to reduce the
+ severity level. But the following text now says the [variable] "*should*
+ only be used to specify"... instead of previously having said "may".
+
+- multi: remove data->state.current_conn struct field
+
+ Not needed
+
+- multi: remove the one_easy struct field
+
+ Since the merge of SessionHandle with Curl_one_easy, this indirection
+ isn't used anymore.
+
+- multi: rename all Curl_one_easy to SessionHandle
+
+- multi: remove the multi_pos struct field
+
+ Since Curl_one_easy is really a SessionHandle now, this indirection
+ doesn't exist anymore.
+
+- multi: remove easy_handle struct field
+
+ It isn't needed anymore
+
+- multi: remove 'Curl_one_easy' struct, phase 1
+
+ The motivation for having a separate struct that keep track of an easy
+ handle when using the multi handle was removed when we switched to
+ always using the multi interface internally. Now they were just two
+ separate struct that was always allocated for each easy handle.
+
+ This first step just moves the Curl_one_easy struct members into the
+ SessionHandle struct and hides this somehow (== keeps the source code
+ changes to a minimum) by defining Curl_one_easy to SessionHandle
+
+ The biggest changes in this commit are:
+
+ 1 - the linked list of easy handles had to be changed somewhat due
+ to the new struct layout. This made the main linked list pointer
+ get renamed to 'easyp' and there's also a new pointer to the last
+ node, called easylp. It is no longer circular but ends with ->next
+ pointing to NULL. New nodes are still added last.
+
+ 2 - easy->state is now called easy->mstate to avoid name collision
+
+Steve Holme (2 Aug 2013)
+- Revert "DOCS: Added IMAP URL example for listing new messages"
+
+ This reverts commit 82ab5f1b0c7c3f as this was the wrong place to
+ document the complexity of IMAP URLs and Custom Requests.
+
+- DOCS: Added IMAP URL example for listing new messages
+
+ In addition to listing the folder contents, in the URL examples, added
+ an example to list the new messages waiting in the user's inbox.
+
+Yang Tse (1 Aug 2013)
+- packages/vms/Makefile.am: add latest file additions to EXTRA_DIST
+
+- [John Malmberg brought this change]
+
+ Add in the files needed to build libcurl shared images on VMS.
+
+ Update the packages/vms/readme file to be current.
+
+ Also some files for the GNV based build were either missing or needed an
+ update.
+
+ curl_crtl_init.c is a special file that is run before main() to
+ set up the proper C runtime behavior.
+
+ generate_vax_transfer.com generates the VAX transfer vector modules from
+ the gnv_libcurl_symbols.opt file.
+
+ gnv_conftest.c_first is a helper file needed for configure scripts to
+ come up with the expected answers on VMS.
+
+ gnv_libcurl_symbols.opt is the public symbols for the libcurl shared
+ image.
+
+ gnv_link_curl.com builds the shared libcurl image and rebuilds other
+ programs to use it.
+
+ macro32_exactcase.patch is a hack to make a local copy of the VMS Macro32
+ assembler case sensitive, which is needed to build the VAX transfer modules.
+
+ report_openssl_version.c is a tool for help verify that the libcurl
+ shared image is being built for a minium version of openssl.
+
+- curl: second follow-up for commit 5af2bfb9
+
+ Display progress-bar unconditionally on first call
+
+- curl: follow-up for commit 5af2bfb9
+
+ Use tvnow() and tvdiff() to avoid introducing new linkage issues
+
+Daniel Stenberg (31 Jul 2013)
+- curl: --progress-bar max update frequency now at 5Hz
+
+- curl: make --progress-bar update the line less frequently
+
+ Also, use memset() instead of a lame loop.
+
+ The previous logic that tried to avoid too many updates were very
+ ineffective for really fast transfers, as then it could easily end up
+ doing hundreds of updates per second that would make a significant
+ impact in transfer performance!
+
+ Bug: http://curl.haxx.se/mail/archive-2013-07/0031.html
+ Reported-by: Marc Doughty
+
+Nick Zitzmann (30 Jul 2013)
+- darwinssl: added LFs to some strings passed into infof()
+
+ (This doesn't need to appear in the release notes.) I noticed a few places
+ where infof() was called, and there should've been an LF at the end of the
+ string, but there wasn't.
+
+- darwinssl: fix build error in crypto authentication under Snow Leopard
+
+ It turns out Snow Leopard not only has SecItemCopyMatching() defined in
+ a header not included by the omnibus header, but it won't work for our
+ purposes, because searching for SecIdentityRef objects wasn't added
+ to that API until Lion. So we now use the old SecKeychainSearch API
+ instead if the user is building under, or running under, Snow Leopard.
+
+ Bug: http://sourceforge.net/p/curl/bugs/1255/
+ Reported by: Edward Rudd
+
+- md5 & metalink: use better build macros on Apple operating systems
+
+ Previously we used __MAC_10_X and __IPHONE_X to mark digest-generating
+ code that was specific to OS X and iOS. Now we use
+ __MAC_OS_X_VERSION_MAX_ALLOWED and __IPHONE_OS_VERSION_MAX_ALLOWED
+ instead of those macros.
+
+ Bug: http://sourceforge.net/p/curl/bugs/1255/
+ Reported by: Edward Rudd
+
+Yang Tse (29 Jul 2013)
+- tool_operhlp.c: fix add_file_name_to_url() OOM handling
+
+- tool_operate.c: fix brace placement for vi/emacs delimiter matching
+
+- tool_operate.c: move <fabdef.h> header inclusion location
+
+Daniel Stenberg (29 Jul 2013)
+- RELEASE-NOTES: synced with b5478a0e033e7
+
+- curl_easy_pause: on unpause, trigger mulit-socket handling
+
+ When the multi-socket API is used, we need the handle to be checked
+ again when it gets unpaused.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-07/0239.html
+ Reported-by: Justin Karneges
+
+- [John E. Malmberg brought this change]
+
+ curl_formadd: fix file upload on VMS
+
+ For the standard VMS text file formats, VMS needs to read the file to
+ get the actual file size.
+
+ For the standard VMS binary file formats, VMS needs a special format of
+ fopen() call so that it stops reading at the logical end of file instead
+ of at the end of the blocks allocated to the file.
+
+ I structured the patch this way as I was not sure about changing the
+ structures or parameters to the routines, but would prefer to only call
+ the stat() function once and pass the information to where the fopen()
+ call is made.
+
+ Bug: https://sourceforge.net/p/curl/bugs/758/
+
+- formadd: CURLFORM_FILECONTENT wrongly rejected some option combos
+
+ The code for CURLFORM_FILECONTENT had its check for duplicate options
+ wrong so that it would reject CURLFORM_PTRNAME if used in combination
+ with it (but not CURLFORM_COPYNAME)! The flags field used for this
+ purpose cannot be interpreted that broadly.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-07/0258.html
+ Reported-by: Byrial Jensen
+
+Yang Tse (25 Jul 2013)
+- packages/vms/Makefile.am: add latest file additions to EXTRA_DIST
+
+- [John E. Malmberg brought this change]
+
+ VMS: intial set of files to allow building using GNV toolkit.
+
+- string formatting: fix too many arguments for format
+
+- string formatting: fix zero-length printf format string
+
+- easy.c: curl_easy_getinfo() fix va_start/va_end matching
+
+- imap.c: imap_sendf() fix va_start/va_end matching
+
+- string formatting: fix 15+ printf-style format strings
+
+Patrick Monnerat (24 Jul 2013)
+- OS400: sync ILE/RPG binding with current curl.h
+
+Yang Tse (24 Jul 2013)
+- string formatting: fix 25+ printf-style format strings
+
+Daniel Stenberg (23 Jul 2013)
+- Makefile.am: use LDFLAGS as well when linking libcurl
+
+ Linking on Solaris 10 x86 with Sun Studio 12 failed when we upgraded
+ automake for the release builds.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1217
+ Reported-by: Dagobert Michelsen
+
+- [Fabian Keil brought this change]
+
+ url.c: Fix dot file path cleanup when using an HTTP proxy
+
+ Previously the path was cleaned, but the URL wasn't properly updated.
+
+- [Fabian Keil brought this change]
+
+ tests: test1232 verifies dotdot removal from path with proxy
+
+- [Fabian Keil brought this change]
+
+ dotdot.c: Fix a RFC section number in a comment for Curl_dedotdotify()
+
+- [John E. Malmberg brought this change]
+
+ build_vms.com: fix debug and float options
+
+ In the reorganization of the build_vms.com the debug and float options
+ were not fixed up correctly.
+
+- [John E. Malmberg brought this change]
+
+ curl: fix upload of a zip file in OpenVMS
+
+ Two fixes:
+
+ 1. Force output file format to be stream-lf so that partial downloads
+ can be continued.
+
+ This should have minor impact as if the file does not exist, it was
+ created with stream-lf format. The only time this was an issue is if
+ there was already an existing file with a different format.
+
+ 2. Fix file uploads are now fixed.
+
+ a. VMS binary files such as ZIP archives are now uploaded
+ correctly.
+
+ b. VMS text files are read once to get the correct size
+ and then converted to line-feed terminated records as
+ they are read into curl.
+
+ The default VMS text formats do not contain either line-feed or
+ carriage-return terminated records. Those delimiters are added by the
+ operating system file read calls if the application requests them.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=496
+
+Yang Tse (22 Jul 2013)
+- libtest: fix data type of some *_setopt() 'long' arguments
+
+- curl: fix symbolic names for CURL_NETRC_* enum in --libcurl output
+
+- curl: fix symbolic names for CURLUSESSL_* enum in --libcurl output
+
+- tool_operate.c: fix passing curl_easy_setopt long arg on some x64 ABIs
+
+ We no longer pass our 'bool' data type variables nor constants as
+ an argument to my_setopt(), instead we use proper 1L or 0L values.
+
+ This also fixes macro used to pass string argument for CURLOPT_SSLCERT,
+ CURLOPT_SSLKEY and CURLOPT_EGDSOCKET using my_setopt_str() instead of
+ my_setopt().
+
+ This also casts enum or int argument data types to long when passed to
+ my_setopt_enum().
+
+Daniel Stenberg (21 Jul 2013)
+- curl_multi_wait: fix revents
+
+ Commit 6d30f8ebed34e7276 didn't work properly. First, it used the wrong
+ array index, but this fix also:
+
+ 1 - only does the copying if indeed there was any activity
+
+ 2 - makes sure to properly translate between internal and external
+ bitfields, which are not guaranteed to match
+
+ Reported-by: Evgeny Turnaev
+
+- RELEASE-NOTES: synced with d529f3882b9bca
+
+- curl_easy_perform: gradually increase the delay time
+
+ Instead of going 50,100,150 etc millisecond delay time when nothing has
+ been found to do or wait for, we now start lower and double each loop as
+ in 4,8,16,32 etc.
+
+ This lowers the minimum wait without sacrifizing the longer wait too
+ much with unnecessary CPU cycles burnt.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-07/0103.html
+ Reported-by: Andreas Malzahn
+
+- ftp_do_more: consider DO_MORE complete when server connects back
+
+ In the case of an active connection when ftp_do_more() detects that the
+ server has connected back, it must make sure to mark it as complete so
+ that the multi_runsingle() function will detect this and move on to the
+ next state.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-07/0115.html
+ Reported-by: Clemens Gruber
+
+Yang Tse (19 Jul 2013)
+- Makefile.b32: Borland makefile adjustments. Tested with BCC 5.5.1
+
+- WIN32 MemoryTracking: require UNICODE for wide strdup code support
+
+Daniel Stenberg (18 Jul 2013)
+- CURLOPT_XFERINFOFUNCTION: introducing a new progress callback
+
+ CURLOPT_XFERINFOFUNCTION is now the preferred progress callback function
+ and CURLOPT_PROGRESSFUNCTION is considered deprecated.
+
+ This new callback uses pure 'curl_off_t' arguments to pass on full
+ resolution sizes. It otherwise retains the same characteristics: the
+ same call rate, the same meanings for the arguments and the return code
+ is used the same way.
+
+ The progressfunc.c example is updated to show how to use the new
+ callback for newer libcurls while supporting the older one if built with
+ an older libcurl or even built with a newer libcurl while running with
+ an older.
+
+Yang Tse (18 Jul 2013)
+- Reinstate "WIN32 MemoryTracking: track wcsdup() _wcsdup() and _tcsdup() usage".
+
+ This reverts commit 7ed25cc, reinstating commit 8ec2cb5.
+
+ As of 18-jul-2013 we still do have code in libcurl that makes use of these
+ memory functions. Commit 8ec2cb5 comment still applies and is yet valid.
+
+ These memory functions are solely used in Windows builds, so all related
+ code is protected with '#ifdef WIN32' preprocessor conditional compilation
+ directives.
+
+ Specifically, wcsdup() _wcsdup() are used when building a Windows target with
+ UNICODE and USE_WINDOWS_SSPI preprocessor symbols defined. This is the case
+ when building a Windows UNICODE target with Windows native SSL/TLS support
+ enabled.
+
+ Realizing that wcsdup() _wcsdup() are used is a bit tricky given that usage
+ of these is hidden behind _tcsdup() which is MS way of dealing with code
+ that must tolerate UNICODE and non-UNICODE compilation. Additionally, MS
+ header files and those compatible from other compilers use this preprocessor
+ conditional compilation directive in order to select at compilation time
+ whether 'wide' or 'ansi' MS API functions are used.
+
+ Without this code, Windows build targets with Windows native SSL/TLS support
+ enabled and MemoryTracking support enabled misbehave in tracking memory usage,
+ regardless of being a UNICODE enabled build or not.
+
+- xc-am-iface.m4: comments refinement
+
+- configure: fix 'subdir-objects' distclean related issue
+
+ See XC_AMEND_DISTCLEAN comments for details.
+
+Daniel Stenberg (18 Jul 2013)
+- [Evgeny Turnaev brought this change]
+
+ curl_multi_wait: set revents for extra fds
+
+ Pass back the revents that happened for the user-provided file
+ descriptors.
+
+- [Ben Greear brought this change]
+
+ asyn-ares: Don't blank ares servers if none configured.
+
+ Best to just let c-ares use it's defaults if none are configured
+ in (lib)curl.
+
+ Signed-off-by: Ben Greear <greearb@candelatech.com>
+
+- [Sergei Nikulov brought this change]
+
+ cmake: Fix for MSVC2010 project generation
+
+ Fixed issue with static build for MSVC2010.
+
+ After some investigation I've discovered known issue
+ http://public.kitware.com/Bug/view.php?id=11240 When .rc file is linked
+ to static lib it fails with following linker error
+
+ LINK : warning LNK4068: /MACHINE not specified; defaulting to X86
+ file.obj : fatal error LNK1112: module machine type 'x64' conflicts with
+ target machine type 'X86'
+
+ Fix add target property /MACHINE: for MSVC generation.
+
+ Also removed old workarounds - it caused errors during msvc build.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-07/0046.html
+
+- mk-ca-bundle.1: point out certdata.txt format docs
+
+Yang Tse (16 Jul 2013)
+- slist.c: Curl_slist_append_nodup() OOM handling fix
+
+Daniel Stenberg (16 Jul 2013)
+- test1414: FTP PORT download without SIZE support
+
+Yang Tse (16 Jul 2013)
+- tests/Makefile.am: add configurehelp.pm to DISTCLEANFILES
+
+Patrick Monnerat (15 Jul 2013)
+- curl_slist_append(): fix error detection
+
+- slist.c: fix indentation
+
+- OS400: new SSL backend GSKit
+
+- OS400: add slist and certinfo EBCDIC support
+
+- config-os400.h: enable system strdup(), strcmpi(), etc.
+
+- x509asn1.c,x509asn1.h: new module to support ASN.1/X509 parsing & info extract
+ Use from qssl backend
+
+- ssluse.c,sslgen.c,sslgen.h: move certinfo support to generic SSL
+
+- Merge branch 'master' of github.com:bagder/curl
+
+ Merge for resync
+
+- slist.c, slist.h, cookie.c: new internal procedure Curl_slist_append_nodup()
+
+Yang Tse (15 Jul 2013)
+- sslgen.c: fix Curl_rand() compiler warning
+
+ Use simple seeding method upon RANDOM_FILE seeding method failure.
+
+- sslgen.c: fix unreleased Curl_rand() infinite recursion
+
+Daniel Stenberg (14 Jul 2013)
+- [Dave Reisner brought this change]
+
+ src/tool: allow timeouts to accept decimal values
+
+ Implement wrappers around strtod to convert the user argument to a
+ double with sane error checking. Use this to allow --max-time and
+ --connect-timeout to accept decimal values instead of strictly integers.
+
+ The manpage is updated to make mention of this feature and,
+ additionally, forewarn that the actual timeout of the operation can
+ vary in its precision (particularly as the value increases in its
+ decimal precision).
+
+- [Dave Reisner brought this change]
+
+ curl.1: fix long line, found by checksrc.pl
+
+- [Dave Reisner brought this change]
+
+ src/tool_paramhlp: try harder to catch negatives
+
+ strto* functions happily chomp off leading whitespace, so simply
+ checking for str[0] can lead to false negatives. Do the full parse and
+ check the out value instead.
+
+- [John E. Malmberg brought this change]
+
+ build_vms.com: detect and use zlib shared image
+
+ Update the build_vms.com to detect and use zlib shared image installed
+ by the ZLIB kit produced by Jean-Francois Pieronne, and the also the
+ future ZLIB 1.2.8 kit in addition to the older ZLIB kits.
+
+ Also fix the indentation to match one of the common standards used for
+ VMS DCL command files and removed the hard tab characters.
+
+ Tested on OpenVMS 8.4 Alpha and IA64, and OpenVMS 7.3 VAX.
+
+Yang Tse (14 Jul 2013)
+- url.c: fix parse_url_login() OOM handling
+
+- http_digest.c: SIGSEGV and OOM handling fixes
+
+- url.c: fix parse_login_details() OOM handling
+
+- [John E. Malmberg brought this change]
+
+ setup-vms.h: sk_pop symbol tweak
+
+ Newer versions of curl are referencing a sk_pop symbol while the HP
+ OpenSSL library has the symbol in uppercase only.
+
+- getinfo.c: fix enumerated type mixed with another type
+
+- test 1511: fix enumerated type mixed with another type
+
+- url.c: fix SIGSEGV
+
+- dotdot.c: fix global declaration shadowing
+
+- easy.c: fix global declaration shadowing
+
+Kamil Dudka (9 Jul 2013)
+- Revert "curl.1: document the --time-cond option in the man page"
+
+ This reverts commit 3a0e931fc715a80004958794a96b12cf90503f99 because
+ the documentation of --time-cond was duplicated by mistake.
+
+ Reported by: Dave Reisner
+
+- curl.1: document the --sasl-ir option in the man page
+
+- curl.1: document the --post303 option in the man page
+
+- curl.1: document the --time-cond option in the man page
+
+Yang Tse (9 Jul 2013)
+- configure: automake 1.14 compatibility tweak (use XC_AUTOMAKE)
+
+- xc-am-iface.m4: provide XC_AUTOMAKE macro
+
+Guenter Knauf (8 Jul 2013)
+- Added winssl-zlib target to VC builds.
+
+- Synced Makefile.vc6 with recent changes.
+
+ Issue posted to the list by malinowsky AT FTW DOT at.
+
+- Added libmetalink URL; added Android versions.
+
+Dan Fandrich (3 Jul 2013)
+- examples: Moved usercertinmem.c to COMPLICATED_EXAMPLES
+
+ This prevents it from being built during a "make check" since it
+ depends on OpenSSL.
+
+Nick Zitzmann (2 Jul 2013)
+- Merge branch 'master' of https://github.com/bagder/curl
+
+- darwinssl: SSLv2 connections are aborted if unsupported by the OS
+
+ I just noticed that OS X no longer supports SSLv2. Other TLS engines return
+ an error if the requested protocol isn't supported by the underlying
+ engine, so we do that now for SSLv2 if the framework returns an error
+ when trying to turn on SSLv2 support. (Note: As always, SSLv2 support is
+ only enabled in curl when starting the app with the -2 argument; it's off
+ by default. SSLv2 is really old and insecure.)
+
+Marc Hoersken (1 Jul 2013)
+- lib506.c: Fixed possible use of uninitialized variables
+
+Kamil Dudka (30 Jun 2013)
+- url: restore the functionality of 'curl -u :'
+
+ This commit fixes a regression introduced in
+ fddb7b44a79d78e05043e1c97e069308b6b85f79.
+
+ Reported by: Markus Moeller
+ Bug: http://curl.haxx.se/mail/archive-2013-06/0052.html
+
+Daniel Stenberg (25 Jun 2013)
+- digest: append the timer to the random for the nonce
+
+- digest: improve nonce generation
+
+ Use the new improved Curl_rand() to generate better random nonce for
+ Digest auth.
+
+- curl.1: fix typo in --xattr description
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1252
+ Reported-by: Jean-Noël Rouvignac
+
+- RELEASE-NOTES: synced with 365c5ba39591
+
+ The 10 first bug fixes for the pending release...
+
+- formpost: better random boundaries
+
+ When doing multi-part formposts, libcurl used a pseudo-random value that
+ was seeded with time(). This turns out to be bad for users who formpost
+ data that is provided with users who then can guess how the boundary
+ string will look like and then they can forge a different formpost part
+ and trick the receiver.
+
+ My advice to such implementors is (still even after this change) to not
+ rely on the boundary strings being cryptographically strong. Fix your
+ code and logic to not depend on them that much!
+
+ I moved the Curl_rand() function into the sslgen.c source file now to be
+ able to take advantage of the SSL library's random function if it
+ provides one. If not, try to use the RANDOM_FILE for seeding and as a
+ last resort keep the old logic, just modified to also add microseconds
+ which makes it harder to properly guess the exact seed.
+
+ The formboundary() function in formdata.c is now using 64 bit entropy
+ for the boundary and therefore the string of dashes was reduced by 4
+ letters and there are 16 hex digits following it. The total length is
+ thus still the same.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1251
+ Reported-by: "Floris"
+
+- printf: make sure %x are treated unsigned
+
+ When using %x, the number must be treated as unsigned as otherwise it
+ would get sign-extended on for example 64bit machines and do wrong
+ output. This problem showed when doing printf("%08x", 0xffeeddcc) on a
+ 64bit host.
+
+- tests: add test1395 to the tarball
+
+- SIGPIPE: don't use 'data' in sigpipe restore
+
+ Follow-up fix from 7d80ed64e43515.
+
+ The SessionHandle may not be around to use when we restore the sigpipe
+ sighandler so we store the no_signal boolean in the local struct to know
+ if/how to restore.
+
+- TODO: 1.8 Modified buffer size approach
+
+ Thoughts around buffer sizes and what might be possible to do...
+
+- c-ares: improve error message on failed resolve
+
+ When the c-ares based resolver backend failed to resolve a name, it
+ tried to show the name that failed from existing structs. This caused
+ the wrong output and shown hostname when for example --interface
+ [hostname] was used and that name resolving failed.
+
+ Now we use the hostname used in the actual resolve attempt in the error
+ message as well.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1191
+ Reported-by: Kim Vandry
+
+- ossl_recv: check for an OpenSSL error, don't assume
+
+ When we recently started to treat a zero return code from SSL_read() as
+ an error we also got false positives - which primarily looks to be
+ because the OpenSSL documentation is wrong and a zero return code is not
+ at all an error case in many situations.
+
+ Now ossl_recv() will check with ERR_get_error() to see if there is a
+ stored error and only then consider it to be a true error if SSL_read()
+ returned zero.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1249
+ Reported-by: Nach M. S.
+ Patch-by: Nach M. S.
+
+Nick Zitzmann (22 Jun 2013)
+- Merge branch 'master' of https://github.com/bagder/curl
+
+- darwinssl: fix crash that started happening in Lion
+
+ Something (a recent security update maybe?) changed in Lion, and now it
+ has changed SSLCopyPeerTrust such that it may return noErr but also give
+ us a null trust, which caught us off guard and caused an eventual crash.
+
+Daniel Stenberg (22 Jun 2013)
+- SIGPIPE: ignored while inside the library
+
+ ... and restore the ordinary handling again when it returns. This is
+ done for curl_easy_perform() and curl_easy_cleanup() only for now - and
+ only when built to use OpenSSL as backend as this is the known culprit
+ for the spurious SIGPIPEs people have received.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1180
+ Reported by: Lluís Batlle i Rossell
+
+- KNOWN_BUGS: #83 unable to load non-default openssl engines
+
+- test1396: invoke the correct test tool!
+
+ This erroneously run unit test 1310 instead of 1396!
+
+Kamil Dudka (22 Jun 2013)
+- test1230: avoid using hard-wired port number
+
+ ... to prevent failure when a non-default -b option is given
+
+- curl-config.in: replace tabs by spaces
+
+Nick Zitzmann (22 Jun 2013)
+- darwinssl: reform OS-specific #defines
+
+ This doesn't need to be in the release notes. I cleaned up a lot of the #if
+ lines in the code to use MAC_OS_X_VERSION_MIN_REQUIRED and
+ MAC_OS_X_VERSION_MAX_ALLOWED instead of checking for whether things like
+ __MAC_10_6 or whatever were defined, because for some SDKs Apple has released
+ they were defined out of place.
+
+Daniel Stenberg (22 Jun 2013)
+- [Alessandro Ghedini brought this change]
+
+ docs: fix typo in curl_easy_getinfo manpage
+
+- dotdot: introducing dot file path cleanup
+
+ RFC3986 details how a path part passed in as part of a URI should be
+ "cleaned" from dot sequences before getting used. The described
+ algorithm is now implemented in lib/dotdot.c with the accompanied test
+ case in test 1395.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1200
+ Reported-by: Alex Vinnik
+
+- bump: start working towards what most likely will become 7.32.0
+
+- THANKS: added 24 new contributors from the 7.31.0 release
+
+Version 7.31.0 (22 Jun 2013)
+
+Daniel Stenberg (22 Jun 2013)
+- RELEASE-NOTES: synced with 0de7249bb39a2 - 7.31.0
+
+- unit1396: unit tests to verify curl_easy_(un)escape
+
+- Curl_urldecode: no peeking beyond end of input buffer
+
+ Security problem: CVE-2013-2174
+
+ If a program would give a string like "%FF" to curl_easy_unescape() but
+ ask for it to decode only the first byte, it would still parse and
+ decode the full hex sequence. The function then not only read beyond the
+ allowed buffer but it would also deduct the *unsigned* counter variable
+ for how many more bytes there's left to read in the buffer by two,
+ making the counter wrap. Continuing this, the function would go on
+ reading beyond the buffer and soon writing beyond the allocated target
+ buffer...
+
+ Bug: http://curl.haxx.se/docs/adv_20130622.html
+ Reported-by: Timo Sirainen
+
+Guenter Knauf (20 Jun 2013)
+- Use opened body.out file and write content to it.
+
+Daniel Stenberg (20 Jun 2013)
+- multi_socket: react on socket close immediately
+
+ As a remedy to the problem when a socket gets closed and a new one is
+ opened with the same file descriptor number and as a result
+ multi.c:singlesocket() doesn't detect the difference, the new function
+ Curl_multi_closed() gets told when a socket is closed so that it can be
+ removed from the socket hash. When the old one has been removed, a new
+ socket should be detected fine by the singlesocket() on next invoke.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1248
+ Reported-by: Erik Johansson
+
+- RELEASE-NOTES: synced with e305f5ec715f
+
+- TODO: mention the DANE patch from March
+
+- CURLOPT_COOKIELIST: take cookie share lock
+
+ When performing COOKIELIST operations the cookie lock needs to be taken
+ for the cases where the cookies are shared among multiple handles!
+
+ Verified by Benjamin Gilbert's updated test 506
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1215
+ Reported-by: Benjamin Gilbert
+
+- [Benjamin Gilbert brought this change]
+
+ test506: verify that CURLOPT_COOKIELIST takes share lock
+
+ It doesn't right now: http://curl.haxx.se/bug/view.cgi?id=1215
+
+- TODO: HTTP2/SPDY support
+
+- curl_easy_setopt.3: clarify CURLOPT_PROGRESSFUNCTION frequency
+
+ Make it clearer that the CURLOPT_PROGRESSFUNCTION callback will be
+ called more frequently than once per second when things are happening.
+
+- RELEASE-NOTES: synced with 9c3e098259b82
+
+ Mention 7 recent bug fixes and their associated contributors
+
+- curl_multi_wait.3: clarify the numfds counter
+
+- curl_easy_perform: avoid busy-looping
+
+ When curl_multi_wait() finds no file descriptor to wait for, it returns
+ instantly and this must be handled gracefully within curl_easy_perform()
+ or cause a busy-loop. Starting now, repeated fast returns without any
+ file descriptors is detected and a gradually increasing sleep will be
+ used (up to a max of 1000 milliseconds) before continuing the loop.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1238
+ Reported-by: Miguel Angel
+
+- [YAMADA Yasuharu brought this change]
+
+ cookies: follow-up fix for path checking
+
+ The initial fix to only compare full path names were done in commit
+ 04f52e9b4db0 but found out to be incomplete. This takes should make the
+ change more complete and there's now two additional tests to verify
+ (test 31 and 62).
+
+- [Sergei Nikulov brought this change]
+
+ lib1900: use tutil_tvnow instead of gettimeofday
+
+ Makes it build on windows
+
+- [Eric Hu brought this change]
+
+ axtls: now done non-blocking
+
+- [Eric Hu brought this change]
+
+ test2033: requires NTLM support
+
+- KNOWN_BUGS: #82 failed build with Borland compiler
+
+- Curl_output_digest: support auth-int for empty entity body
+
+ By always returning the md5 for an empty body when auth-int is asked
+ for, libcurl now at least sometimes does the right thing.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1235
+ Patched-by: Nach M. S.
+
+- multi_socket: reduce timeout inaccuracy margin
+
+ Allow less room for "triggered too early" mistakes by applications /
+ timers on non-windows platforms. Starting now, we assume that a timeout
+ call is never made earlier than 3 milliseconds before the actual
+ timeout. This greatly improves timeout accuracy on Linux.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1228
+ Reported-by: Hang Su
+
+- cert_stuff: avoid double free in the PKCS12 code
+
+ In the pkcs12 code, we get a list of x509 records returned from
+ PKCS12_parse but when iterating over the list and passing each to
+ SSL_CTX_add_extra_chain_cert() we didn't also properly remove them from
+ the "stack", which made them get freed twice (both in sk_X509_pop_free()
+ and then later in SSL_CTX_free).
+
+ This isn't really documented anywhere...
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1236
+ Reported-by: Nikaiw
+
+- cert_stuff: remove code duplication in the pkcs12 logic
+
+- [Aleksey Tulinov brought this change]
+
+ axtls: honor disabled VERIFYHOST
+
+ When VERIFYHOST == 0, libcurl should let invalid certificates to pass.
+
+- [Peter Gal brought this change]
+
+ curl_easy_setopt.3: HTTP header with no content
+
+ Update the documentation on how to specify a HTTP header with no
+ content.
+
+- RELEASE-NOTES: synced with 87cf677eca55
+
+ Added 11 bugs and 7 contributors
+
+- lib1500: remove bad check
+
+ After curl_multi_wait() returns, this test checked that we got exactly
+ one file descriptor told to read from, but we cannot be sure that is
+ true. curl_multi_wait() will sometimes return earlier without any file
+ descriptor to handle, just just because it is a suitable time to call
+ *perform().
+
+ This problem showed up with commit 29bf0598.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-06/0029.html
+ Reported-by: Fabian Keil
+
+- tests/Makefile: typo in the perlcheck target
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1239
+ Reported-by: Christian Weisgerber
+
+- test1230: verify CONNECT to a numerical ipv6-address
+
+- sws: support extracting test number from CONNECT ipv6-address!
+
+ If an ipv6-address is provided to CONNECT, the last hexadecimal group in
+ the address will be used as the test number! For example the address
+ "[1234::ff]" would be treated as test case 255.
+
+- curl_multi_wait: only use internal timer if not -1
+
+ commit 29bf0598aad5 introduced a problem when the "internal" timeout is
+ prefered to the given if shorter, as it didn't consider the case where
+ -1 was returned. Now the internal timeout is only considered if not -1.
+
+ Reported-by: Tor Arntsen
+ Bug: http://curl.haxx.se/mail/lib-2013-06/0015.html
+
+Dan Fandrich (3 Jun 2013)
+- libcurl-tutorial.3: added a section on IPv6
+
+ Also added a (correctly-escaped) backslash to the autoexec.bat
+ example file and a new Windows character device name with
+ a colon as examples of other characters that are special
+ and potentially dangerous (this reverts and reworks commit
+ 7d8d2a54).
+
+Daniel Stenberg (3 Jun 2013)
+- curl_multi_wait: reduce timeout if the multi handle wants to
+
+ If the multi handle's pending timeout is less than what is passed into
+ this function, it will now opt to use the shorter time anyway since it
+ is a very good hint that the handle wants to process something in a
+ shorter time than what otherwise would happen.
+
+ curl_multi_wait.3 was updated accordingly to clarify
+
+ This is the reason for bug #1224
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1224
+ Reported-by: Andrii Moiseiev
+
+- multi_runsingle: switch an if() condition for readability
+
+ ... because there's an identical check right next to it so using the
+ operators in the check in the same order increases readability.
+
+Marc Hoersken (2 Jun 2013)
+- curl_schannel.c: Removed variable unused since 35874298e4
+
+- curl_setup.h: Fixed redefinition warning using mingw-w64
+
+Daniel Stenberg (30 May 2013)
+- multi_runsingle: add braces to clarify the code
+
+- libcurl-tutorial.3: remove incorrect backslash
+
+ A single backslash in the content is not legal nroff syntax.
+
+ Reported and fixed by: Eric S. Raymond
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1234
+
+- curl_formadd.3: fixed wrong "end-marker" syntax
+
+ Reported and fixed by: Eric S. Raymond
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1233
+
+- curl.1: clarify that --silent still outputs data
+
+- Digest auth: escape user names with \ or " in them
+
+ When sending the HTTP Authorization: header for digest, the user name
+ needs to be escaped if it contains a double-quote or backslash.
+
+ Test 1229 was added to verify
+
+ Reported and fixed by: Nach M. S
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1230
+
+- [Mike Giancola brought this change]
+
+ ossl_recv: SSL_read() returning 0 is an error too
+
+ SSL_read can return 0 for "not successful", according to the open SSL
+ documentation: http://www.openssl.org/docs/ssl/SSL_read.html
+
+- [Mike Giancola brought this change]
+
+ ossl_send: SSL_write() returning 0 is an error too
+
+ We found that in specific cases if the connection is abruptly closed,
+ the underlying socket is listed in a close_wait state. We continue to
+ call the curl_multi_perform, curl_mutli_fdset etc. None of these APIs
+ report the socket closed / connection finished. Since we have cases
+ where the multi connection is only used once, this can pose a problem
+ for us. I've read that if another connection was to come in, curl would
+ see the socket as bad and attempt to close it at that time -
+ unfortunately, this does not work for us.
+
+ I found that in specific situations, if SSL_write returns 0, curl did
+ not recognize the socket as closed (or errored out) and did not report
+ it to the application. I believe we need to change the code slightly, to
+ check if ssl_write returns 0. If so, treat it as an error - the same as
+ a negative return code.
+
+ For OpenSSL - the ssl_write documentation is here:
+ http://www.openssl.org/docs/ssl/SSL_write.html
+
+- KNOWN_BUGS: curl -OJC- fails to resume
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1169
+
+- Curl_cookie_add: handle IPv6 hosts
+
+ 1 - don't skip host names with a colon in them in an attempt to bail out
+ on HTTP headers in the cookie file parser. It was only a shortcut anyway
+ and trying to parse a file with HTTP headers will still be handled, only
+ slightly slower.
+
+ 2 - don't skip domain names based on number of dots. The original
+ netscape cookie spec had this oddity mentioned and while our code
+ decreased the check to only check for two, the existing cookie spec has
+ no such dot counting required.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1221
+ Reported-by: Stefan Neis
+
+- curl_easy_setopt.3: expand the PROGRESSFUNCTION section
+
+ Explain the callback and its arguments better and with more descriptive
+ text.
+
+- tests: add test1394 file to the tarball
+
+- tarball: include the xmlstream example
+
+- [David Strauss brought this change]
+
+ xmlstream: XML stream parsing example source code
+
+ Add an XML stream parsing example using Expat. Add missing ignore for
+ the binary from an unrelated example.
+
+- [YAMADA Yasuharu brought this change]
+
+ cookies: only consider full path matches
+
+ I found a bug which cURL sends cookies to the path not to aim at.
+ For example:
+ - cURL sends a request to http://example.fake/hoge/
+ - server returns cookie which with path=/hoge;
+ the point is there is NOT the '/' end of path string.
+ - cURL sends a request to http://example.fake/hogege/ with the cookie.
+
+ The reason for this old "feature" is because that behavior is what is
+ described in the original netscape cookie spec:
+ http://curl.haxx.se/rfc/cookie_spec.html
+
+ The current cookie spec (RFC6265) clarifies the situation:
+ http://tools.ietf.org/html/rfc6265#section-5.2.4
+
+- [Eric Hu brought this change]
+
+ axtls: prevent memleaks on SSL handshake failures
+
+- Revert "WIN32 MemoryTracking: track wcsdup() _wcsdup() and _tcsdup() usage"
+
+ This reverts commit 8ec2cb5544b86306b702484ea785b6b9596562ab.
+
+ We don't have any code anywhere in libcurl (or the curl tool) that use
+ wcsdup so there's no such memory use to track. It seems to cause mild
+ problems with the Borland compiler though that we may avoid by reverting
+ this change again.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-05/0070.html
+
+- RELEASE-NOTES: synced with ae26ee3489588f0
+
+Guenter Knauf (11 May 2013)
+- Updated zlib version in build files.
+
+Daniel Stenberg (9 May 2013)
+- [Renaud Guillard brought this change]
+
+ OS X framework: fix invalid symbolic link
+
+Kamil Dudka (9 May 2013)
+- [Daniel Stenberg brought this change]
+
+ nss: give PR_INTERVAL_NO_WAIT instead of -1 to PR_Recv/PR_Send
+
+ Reported by: David Strauss
+ Bug: http://curl.haxx.se/mail/lib-2013-05/0088.html
+
+Daniel Stenberg (8 May 2013)
+- libtest: gitignore more binary files
+
+- servercert: allow empty subject
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1220
+ Patch by: John Gardiner Myers
+
+- [Steve Holme brought this change]
+
+ tests: Added new SMTP tests to verify commit 99b40451836d
+
+- runtests.pl: support nonewline="yes" in client/stdin sections
+
+- build: fixed unit1394 for debug and metlink builds
+
+Kamil Dudka (6 May 2013)
+- unit1394.c: plug the curl tool unit test in
+
+- [Jared Jennings brought this change]
+
+ unit1394.c: basis of a unit test for parse_cert_parameter()
+
+- src/Makefile.am: build static lib for unit tests if enabled
+
+- tool_getparam: ensure string termination in parse_cert_parameter()
+
+- tool_getparam: fix memleak in handling the -E option
+
+- tool_getparam: describe what parse_cert_parameter() does
+
+ ... and de-duplicate the code initializing *passphrase
+
+- curl.1: document escape sequences recognized by -E
+
+- [Jared Jennings brought this change]
+
+ curl -E: allow to escape ':' in cert nickname
+
+Marc Hoersken (5 May 2013)
+- curl_schannel.c: Fixed invalid memory access during SSL shutdown
+
+Steve Holme (4 May 2013)
+- smtp: Fix trailing whitespace warning
+
+- smtp: Fix compilation warning
+
+ comparison between signed and unsigned integer expressions
+
+- RELEASE-NOTES: synced with 92ef5f19c801
+
+- smtp: Updated RFC-2821 references to RFC-5321
+
+- smtp: Fixed sending of double CRLF caused by first in EOB
+
+ If the mail sent during the transfer contains a terminating <CRLF> then
+ we should not send the first <CRLF> of the EOB as specified in RFC-5321.
+
+ Additionally don't send the <CRLF> if there is "no mail data" as the
+ DATA command already includes it.
+
+- tests: Corrected MAIL SIZE for CRLF line endings
+
+ ... which was missed in commit: f5c3d9538452
+
+- tests: Corrected infilesize for CRLF line endings
+
+ ... which was missed in commit: f5c3d9538452
+
+- tests: Corrected test1406 to be RFC2821 compliant
+
+- tests: Corrected test1320 to be RFC2821 compliant
+
+- tests: Corrected typo in test909
+
+ Introduced in commit: 514817669e9e
+
+- tests: Corrected test909 to be RFC2821 compliant
+
+- tests: Updated test references to 909 from 1411
+
+ ...and removed references to libcurl and test1406.
+
+- tests: Renamed test1411 to test909 as this is a main SMTP test
+
+Daniel Stenberg (1 May 2013)
+- [Lars Johannesen brought this change]
+
+ bindlocal: move brace out of #ifdef
+
+ The code within #ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID wrongly had two
+ closing braces when it should only have one, so builds without that
+ define would fail.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-05/0000.html
+
+Steve Holme (30 Apr 2013)
+- smtp: Tidy up to move the eob counter to the per-request structure
+
+ Move the eob counter from the smtp_conn structure to the SMTP structure
+ as it is associated with a SMTP payload on a per-request basis.
+
+- TODO: Updated following the addition of CURLOPT_SASL_IR
+
+- smtp: Fixed unknown percentage complete in progress bar
+
+ The curl command line utility would display the the completed progress
+ bar with a percentage of zero as the progress routines didn't know the
+ size of the transfer.
+
+Daniel Stenberg (29 Apr 2013)
+- ftpserver: silence warnings
+
+ Fix regressions in commit b56e3d43e5d. Make @data local and filter off
+ non-numerical digits from $testno in STATUS_imap.
+
+Steve Holme (29 Apr 2013)
+- ftpserver.pl: Corrected the imap LOGIN response
+
+ ...to be more realistic and consistent with the other imap responses.
+
+- tests: Added imap STATUS command test
+
+- tests: Corrected the SMTP tests to be RFC2821 compliant
+
+ The emails that are sent to the server during these tests were
+ incorrectly formatted as they contained one or more LF terminated lines
+ rather than being CRLF terminated as per Section 2.3.7 of RFC-2821.
+
+ This wasn't a problem for the test suite as the <stdin> data matched the
+ <upload> data but anyone using these tests as reference would be sending
+ incorrect data to a server.
+
+- email: Tidy up of *_perform_authenticate()
+
+ Removed the hard returns from imap and pop3 by using the same style for
+ sending the authentication string as smtp. Moved the "Other mechanisms
+ not supported" check in smtp to match that of imap and pop3 to provide
+ consistency between the three email protocols.
+
+- smtp: Updated limit check to be more readable like the check in pop3
+
+- pop3: Added 255 octet limit check when sending initial response
+
+ Added 255 octet limit check as per Section 4. Paragraph 8 of RFC-5034.
+
+- DOCS: Corrected line length of recent Secure Transport changes
+
+Nick Zitzmann (27 Apr 2013)
+- darwinssl: add TLS crypto authentication
+
+ Users using the Secure Transport (darwinssl) back-end can now use a
+ certificate and private key to authenticate with a site using TLS. Because
+ Apple's security system is based around the keychain and does not have any
+ non-public function to create a SecIdentityRef data structure from data
+ loaded outside of the Keychain, the certificate and private key have to be
+ loaded into the Keychain first (using the certtool command line tool or
+ the Security framework's C API) before we can find it and use it.
+
+Steve Holme (27 Apr 2013)
+- Corrected version numbers after bump
+
+Daniel Stenberg (27 Apr 2013)
+- bump version
+
+ Since we're adding new stuff, the next release will bump the minor
+ version and we're looking forward to 7.31.0
+
+Steve Holme (27 Apr 2013)
+- RELEASE-NOTES: synced with f4e6e201b146
+
+- DOCS: Updated following the addition of CURLOPT_SASL_IR
+
+ Documented the the option in curl_easy_setopt() and added it to
+ symbols-in-versions.
+
+- tests: Corrected command line arguments in test907 and test908
+
+- tests: Added SMTP AUTH with initial response tests
+
+- tests: Updated SMTP tests to decouple client initial response
+
+ Updated test903 and test904 following the addition of CURLOPT_SASL_IR
+ as the default behaviour of SMTP AUTH responses is now to not include
+ the initial response. New tests with --sasl-ir support to follow.
+
+- imap: Added support for overriding the SASL initial response
+
+ In addition to checking for the SASL-IR capability the user can override
+ the sending of the client's initial response in the AUTHENTICATION
+ command with the use of CURLOPT_SASL_IR should the server erroneously
+ not report SASL-IR when it does support it.
+
+- smtp: Added support for disabling the SASL initial response
+
+ Updated the default behaviour of sending the client's initial response in the AUTH
+ command to not send it and added support for CURLOPT_SASL_IR to allow the user to
+ specify including the response.
+
+ Related Bug: http://curl.haxx.se/mail/lib-2012-03/0114.html
+ Reported-by: Gokhan Sengun
+
+- pop3: Added support for enabling the SASL initial response
+
+ Allowed the user to specify whether to send the client's intial response
+ in the AUTH command via CURLOPT_SASL_IR.
+
+- sasl-ir: Added --sasl-ir option to curl command line tool
+
+- sasl-ir: Added CURLOPT_SASL_IR to enable/disable the SASL initial response
+
+Daniel Stenberg (26 Apr 2013)
+- curl_easy_init: use less mallocs
+
+ By introducing an internal alternative to curl_multi_init() that accepts
+ parameters to set the hash sizes, easy handles will now use tiny socket
+ and connection hash tables since it will only ever add a single easy
+ handle to that multi handle.
+
+ This decreased the number mallocs in test 40 (which is a rather simple
+ and typical easy interface use case) from 1142 to 138. The maximum
+ amount of memory allocated used went down from 118969 to 78805.
+
+Steve Holme (26 Apr 2013)
+- ftpserver.pl: Fixed imap logout confirmation data
+
+ An IMAP server should response with the BYE continuation response before
+ confirming the LOGOUT command was successful.
+
+Daniel Stenberg (26 Apr 2013)
+- ftp_state_pasv_resp: connect through proxy also when set by env
+
+ When connecting back to an FTP server after having sent PASV/EPSV,
+ libcurl sometimes didn't use the proxy properly even though the proxy
+ was used for the initial connect.
+
+ The function wrongly checked for the CURLOPT_PROXY variable to be set,
+ which made it act wrongly if the proxy information was set with an
+ environment variable.
+
+ Added test case 711 to verify (based on 707 which uses --socks5). Also
+ added test712 to verify another variation of setting the proxy: with
+ --proxy socks5://
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1218
+ Reported-by: Zekun Ni
+
+Kamil Dudka (26 Apr 2013)
+- [Zdenek Pavlas brought this change]
+
+ url: initialize speed-check data for file:// protocol
+
+ ... in order to prevent an artificial timeout event based on stale
+ speed-check data from a previous network transfer. This commit fixes
+ a regression caused by 9dd85bced56f6951107f69e581c872c1e7e3e58e.
+
+ Bug: https://bugzilla.redhat.com/906031
+
+Daniel Stenberg (25 Apr 2013)
+- test709: clarify the test in the name
+
+- sshserver: disable StrictHostKeyChecking
+
+ I couldn't figure out why the host key logic isn't working, but having
+ it set to yes prevents my SSH-based test cases to run. I also don't see
+ a strong need to use strict host key checking on this test server.
+
+ So I disabled it.
+
+- runtests: log more commands in verbose mode
+
+ ... to aid tracking down failures
+
+Steve Holme (25 Apr 2013)
+- TODO: Corrected copy/paste typo
+
+- TODO: Added new ideas for future SMTP, POP3 and IMAP features
+
+- TODO: Updated following the addition of ;auth=<MECH> support
+
+- DOCS: Minor rewording / clarification of host name protocol detection
+
+- RELEASE-NOTES: synced with a8c92cb60890
+
+- DOCS: Added reference to IETF draft for SMTP URL Interface
+
+ ...when mentioning login options. Additional minor clarification of
+ "Windows builds" to be "Windows builds with SSPI"as a way of enabling
+ NTLM as Windows builds may be built with OpenSSL to enable NTLM or
+ without NTLM support altogether.
+
+Linus Nielsen Feltzing (23 Apr 2013)
+- HISTORY: Fix spelling error.
+
+Steve Holme (23 Apr 2013)
+- DOCS: Reworked the scheme calculation explanation under CURLOPT_URL
+
+- url: Added smtp and pop3 hostnames to the protocol detection list
+
+Daniel Stenberg (23 Apr 2013)
+- HISTORY: correct some years/dates
+
+ Thanks to archive.org's wayback machine I updated this document with
+ some facts from the early httpget/urlget web page:
+
+ http://web.archive.org/web/19980216125115/http://www.inf.ufrgs.br/~sagula/urlget.html
+
+- [Alessandro Ghedini brought this change]
+
+ tests: add test1511 to check timecond clean-up
+
+ Verifies the timecond fix in commit c49ed0b6c0f
+
+- [Alessandro Ghedini brought this change]
+
+ getinfo.c: reset timecond when clearing session-info variables
+
+ Bug: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=705783
+ Reported-by: Ludovico Cavedon <cavedon@debian.org>
+
+Steve Holme (22 Apr 2013)
+- DOCS: Added information about login options to CURLOPT_USERPWD
+
+- DOCS: Added information about login options in the URL
+
+- url: Fixed missing length check in parse_proxy()
+
+ Commit 11332577b3cb removed the length check that was performed by the
+ old scanf() code.
+
+- url: Fixed crash when no username or password supplied for proxy
+
+ Fixed an issue in parse_proxy(), introduced in commit 11332577b3cb,
+ where an empty username or password (For example: http://:@example.com)
+ would cause a crash.
+
+- url: Removed unused text length constants
+
+- url: Updated proxy URL parsing to use parse_login_details()
+
+- url: Tidy up of setstropt_userpwd() parameters
+
+ Updated the naming convention of the login parameters to match those of
+ other functions.
+
+- url: Tidy up of code and comments following recent changes
+
+ Tidy up of variable names and comments in setstropt_userpwd() and
+ parse_login_details().
+
+- url: Simplified setstropt_userpwd() following recent changes
+
+ There is no need to perform separate clearing of data if a NULL option
+ pointer is passed in. Instead this operation can be performed by simply
+ not calling parse_login_details() and letting the rest of the code do
+ the work.
+
+- url: Correction to scope of if statements when setting data
+
+- url: Fixed memory leak in setstropt_userpwd()
+
+ setstropt_userpwd() was calling setstropt() in commit fddb7b44a79d to
+ set each of the login details which would duplicate the strings and
+ subsequently cause a memory leak.
+
+- RELEASE-NOTES: synced with d535c4a2e1f7
+
+- url: Added overriding of URL login options from CURLOPT_USERPWD
+
+- tool_paramhlp: Fixed options being included in username
+
+ Fix to prevent the options from being displayed when curl requests the
+ user's password if the following command line is specified:
+
+ --user username;options
+
+- url: Added support for parsing login options from the CURLOPT_USERPWD
+
+ In addition to parsing the optional login options from the URL, added
+ support for parsing them from CURLOPT_USERPWD, to allow the following
+ supported command line:
+
+ --user username:password;options
+
+- url: Added bounds checking to parse_login_details()
+
+ Added bounds checking when searching for the separator characters within
+ the login string as this string may not be NULL terminated (For example
+ it is the login part of a URL). We do this in preference to allocating a
+ new string to copy the login details into which could then be passed to
+ parse_login_details() for performance reasons.
+
+- url: Added size_t cast to pointer based length calculations
+
+- url: Corrected minor typo in comment
+
+Daniel Stenberg (18 Apr 2013)
+- CURL_CHECK_CA_BUNDLE: don't check for paths when cross-compiling
+
+ When cross-compiling we can't scan and detect existing files or paths.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-04/0294.html
+
+- [Ishan SinghLevett brought this change]
+
+ usercertinmem.c: add example showing user cert in memory
+
+ Relies on CURLOPT_SSL_CTX_FUNCTION, which is OpenSSL specific
+
+Steve Holme (18 Apr 2013)
+- url: Fix chksrc longer than 79 columns warning
+
+- url: Fix incorrect variable type for result code
+
+- url: Fix compiler warning
+
+ signed and unsigned type in conditional expression
+
+- url: Moved parsing of login details out of parse_url_login()
+
+ Separated the parsing of login details from the processing of them in
+ parse_url_login() ready for use by setstropt_userpwd().
+
+- url: Re-factored set_userpass() and parse_url_userpass()
+
+ Re-factored these functions to reflect their new behaviour following the
+ addition of login options.
+
+- url: Reworked URL parsing to allow overriding by CURLOPT_USERPWD
+
+Daniel Stenberg (18 Apr 2013)
+- maketgz: make bzip2 creation work with Parallel BZIP2 too
+
+ Apparently the previous usage didn't work with that implementation,
+ while this updated version works with at least both Parallel BZIP2
+ v1.1.8 and regular bzip "Version 1.0.6, 6-Sept-2010".
+
+Linus Nielsen Feltzing (18 Apr 2013)
+- Add tests/http_pipe.py to the tarball build
+
+Steve Holme (16 Apr 2013)
+- smtp: Re-factored all perform based functions
+
+ Standardised the naming of all perform based functions to be in the form
+ smtp_perform_something().
+
+- smtp: Added description comments to all perform based functions
+
+- smtp: Moved smtp_quit() to be with the other perform functions
+
+- smtp: Moved smtp_rcpt_to() to be with the other perform functions
+
+- smtp: Moved smtp_mail() to be with the other perform functions
+
+Daniel Stenberg (16 Apr 2013)
+- [Wouter Van Rooy brought this change]
+
+ curl-config: don't output static libs when they are disabled
+
+ Curl-config outputs static libraries even when they are disabled in
+ configure.
+
+ This causes problems with the build of pycurl.
+
+- [Dave Reisner brought this change]
+
+ docs/libcurl: fix formatting in manpage
+
+ Commit c3ea3eb6 introduced some minor cosmetic errors in
+ curl_mutli_socket_action(3).
+
+- [Paul Howarth brought this change]
+
+ Add extra libs for lib1900 and lib2033 test programs
+
+ These are needed in cases where clock_gettime is used, from librt.
+
+Dan Fandrich (15 Apr 2013)
+- FAQ: mention that the network connection can be monitored
+
+ Also note the prohibition on sharing handles across threads.
+
+Steve Holme (15 Apr 2013)
+- pop3: Added missing comment for pop3_state_apop_resp()
+
+- smtp: Updated the coding style of smtp_state_servergreet_resp()
+
+ Updated the coding style, in this function, to be consistant with other
+ response functions rather then performing a hard return on failure.
+
+- pop3: Updated the coding style of pop3_state_servergreet_resp()
+
+ Updated the coding style, in this function, to be consistent with other
+ response functions rather then performing a hard return on failure.
+
+- pop3: Re-factored all perform based functions
+
+ Standardised the naming of all perform based functions to be in the form
+ pop3_perform_something() following the changes made to IMAP.
+
+- pop3: Added description comments to all perform based functions
+
+- pop3: Moved pop3_quit() to be with the other perform functions
+
+- pop3: Moved pop3_command() to be with the other perform functions
+
+ Started to apply the same tidy up to the POP3 code as applied to the
+ IMAP code in the 7.30.0 release.
+
+- RELEASE-NOTES: Removed erroneous spaces
+
+- RELEASE-NOTES: synced with 8723cade21fb
+
+- smtp: Added support for ;auth=<mech> in the URL
+
+ Added support for specifying the preferred authentication mechanism in
+ the URL as per Internet-Draft 'draft-earhart-url-smtp-00'.
+
+- pop3: Reworked authentication type constants
+
+ ... to use left-shifted values, like those defined in curl.h, rather
+ than 16-bit hexadecimal values.
+
+- pop3: Small consistency tidy up
+
+- pop3: Added support for ;auth=<mech> in the URL
+
+ Added support for specifying the preferred authentication type and SASL
+ mechanism in the URL as per RFC-2384.
+
+- imap: Added support for ;auth=<mech> in the URL
+
+ Added support for specifying the preferred authentication mechanism in
+ the URL as per RFC-5092.
+
+- sasl: Reworked SASL mechanism constants
+
+ ... to use left-shifted values, like those defined in curl.h, rather
+ than 16-bit hexadecimal values.
+
+- sasl: Added predefined preferred mechanism values
+
+ In preparation for the upcoming changes to IMAP, POP3 and SMTP added
+ preferred mechanism values.
+
+- url: Added support for parsing login options from the URL
+
+ As well as parsing the username and password from the URL, added support
+ for parsing the optional options part from the login details, to allow
+ the following supported URL format:
+
+ schema://username:password;options@example.com/path?q=foobar
+
+ This will only be used by IMAP, POP3 and SMTP at present but any
+ protocol that may be given login options in the URL will be able to
+ add support for them.
+
+- smtp: Fix compiler warning
+
+ warning: unused variable 'smtp' introduced in commit 73cbd21b5ee6.
+
+- smtp: Moved parsing of url path into separate function
+
+Daniel Stenberg (12 Apr 2013)
+- FTP: handle a 230 welcome response
+
+ ...instead of the 220 we otherwise expect.
+
+ Made the ftpserver.pl support sending a custom "welcome" and then
+ created test 1219 to verify this fix with such a 230 welcome.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-02/0102.html
+ Reported by: Anders Havn
+
+- configure: try pthread_create without -lpthread
+
+ For libc variants without a spearate pthread lib (like bionic), try
+ using pthreads without the pthreads lib first and only if that fails try
+ the -lpthread linker flag.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1216
+ Reported by: Duncan
+
+- FTP: access files in root dir correctly
+
+ Accessing a file with an absolute path in the root dir but with no
+ directory specified was not handled correctly. This fix comes with four
+ new test cases that verify it.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-04/0142.html
+ Reported by: Sam Deane
+
+Steve Holme (12 Apr 2013)
+- pop3: Reworked the function description for Curl_pop3_write()
+
+- pop3: Added function description to pop3_parse_custom_request()
+
+- pop3: Moved utility functions to end of pop3.c
+
+Nick Zitzmann (12 Apr 2013)
+- darwinssl: add TLS session resumption
+
+ This ought to speed up additional TLS handshakes, at least in theory.
+
+Steve Holme (12 Apr 2013)
+- imap: Added function description to imap_parse_custom_request()
+
+- imap: Moved utility functions to end of imap.c (Part 3/3)
+
+ Moved imap_is_bchar() be with the other utility based functions.
+
+- imap: Moved utility functions to end of imap.c (Part 2/3)
+
+ Moved imap_parse_url_path() and imap_parse_custom_request() to the end of the
+ file allowing all utility functions to be grouped together.
+
+- imap: Moved utility functions to end of imap.c (Part 1/3)
+
+ Moved imap_atom() and imap_sendf() to the end of the file allowing all
+ utility functions to be grouped together.
+
+- imap: Corrected function description for imap_connect()
+
+Kamil Dudka (12 Apr 2013)
+- tests: prevent test206, test1060, and test1061 from failing
+
+ ... in case runtests.pl is invoked with non-default -b option
+
+ Fixes a regression caused by 1e29d275c643ef6aab7948f0f55a7a9397e56b42.
+
+Daniel Stenberg (12 Apr 2013)
+- [David Strauss brought this change]
+
+ libcurl-share.3: update what it does and does not share.
+
+ Update sharing interface documentation to provide exhaustive list of
+ what it does and does not share.
+
+- THANKS: remove duplicated names
+
+- bump: start working towards next release
+
+- THANKS: added people from the 7.30.0 RELEASE-NOTES
+
+Version 7.30.0 (12 Apr 2013)
+
+Daniel Stenberg (12 Apr 2013)
+- RELEASE-NOTES: cleaned up for 7.30 (synced with 5c5e1a1cd20)
+
+ Most notable the security advisory:
+ http://curl.haxx.se/docs/adv_20130412.html
+
+- test1218: another cookie tailmatch test
+
+ ... and make 1216 also verify it with a file input
+
+ These tests verify commit 3604fde3d3c9b0d, the fix for the "cookie
+ domain tailmatch" vulnerability. See
+ http://curl.haxx.se/docs/adv_20130412.html
+
+- [YAMADA Yasuharu brought this change]
+
+ cookie: fix tailmatching to prevent cross-domain leakage
+
+ Cookies set for 'example.com' could accidentaly also be sent by libcurl
+ to the 'bexample.com' (ie with a prefix to the first domain name).
+
+ This is a security vulnerabilty, CVE-2013-1944.
+
+ Bug: http://curl.haxx.se/docs/adv_20130412.html
+
+Guenter Knauf (11 Apr 2013)
+- Enabled MinGW sync resolver builds.
+
+Yang Tse (10 Apr 2013)
+- if2ip.c: fix compiler warning
+
+Guenter Knauf (10 Apr 2013)
+- Fixed lost OpenSSL output with "-t" - followup.
+
+ The previously applied patch didnt work on Windows; we cant rely
+ on shell commands like 'echo' since they act diffently on each
+ platform and each shell.
+ In order to keep this script platform-independent the code must
+ only use pure Perl.
+
+Daniel Stenberg (9 Apr 2013)
+- test1217: verify parsing 257 responses with "rubbish" before path
+
+ Test 1217 verifies commit e0fb2d86c9f78, and without that change this
+ test fails.
+
+- [Bill Middlecamp brought this change]
+
+ FTP: handle "rubbish" in front of directory name in 257 responses
+
+ When doing PWD, there's a 257 response which apparently some servers
+ prefix with a comment before the path instead of after it as is
+ otherwise the norm.
+
+ Failing to parse this, several otherwise legitimate use cases break.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-04/0113.html
+
+Guenter Knauf (9 Apr 2013)
+- Fixed ares-enabled builds with static makefiles.
+
+- Fixed lost OpenSSL output with "-t".
+
+ The OpenSSL pipe wrote to the final CA bundle file, but the encoded PEM
+ output wrote to a temporary file. Consequently, the OpenSSL output was
+ lost when the temp file was renamed to the final file at script finish
+ (overwriting the final file written earlier by openssl).
+ Patch posted to the list by Richard Michael (rmichael edgeofthenet org).
+
+Daniel Stenberg (9 Apr 2013)
+- test1216: test tailmatching cookie domains
+
+ This test is an attempt to repeat the problem YAMADA Yasuharu reported
+ at http://curl.haxx.se/mail/lib-2013-04/0108.html
+
+- RELEASe-NOTES: synced with 29fdb2700f797
+
+ added "tcpkeepalive on Mac OS X"
+
+Nick Zitzmann (8 Apr 2013)
+- darwinssl: disable insecure ciphers by default
+
+ I noticed that aria2's SecureTransport code disables insecure ciphers such
+ as NULL, anonymous, IDEA, and weak-key ciphers used by SSLv3 and later.
+ That's a good idea, and now we do the same thing in order to prevent curl
+ from accessing a "secure" site that only negotiates insecure ciphersuites.
+
+Daniel Stenberg (8 Apr 2013)
+- [Robert Wruck brought this change]
+
+ tcpkeepalive: Support CURLOPT_TCP_KEEPIDLE on OSX
+
+ MacOS X doesn't have TCP_KEEPIDLE/TCP_KEEPINTVL but only a single
+ TCP_KEEPALIVE (see
+ http://developer.apple.com/library/mac/#DOCUMENTATION/Darwin/Reference/ManPages/man4/tcp.4.html).
+ Here is a patch for CURLOPT_TCP_KEEPIDLE on OSX platforms.
+
+- configure: remove CURL_CHECK_FUNC_RECVFROM
+
+ 1 - We don't use the results from the test and we never did. recvfrom()
+ is only used by the TFTP code and it has not caused any problems.
+
+ 2 - the CURL_CHECK_FUNC_RECVFROM function is extremely slow
+
+Steve Holme (8 Apr 2013)
+- RELEASE-NOTES: Corrected duplicate NTLM memory leaks
+
+- RELEASE-NOTES: Removed trailing full stop
+
+Daniel Stenberg (8 Apr 2013)
+- [Fabian Keil brought this change]
+
+ proxy: make ConnectionExists() check credential of proxyconnections too
+
+ Previously it only compared credentials if the requested needle
+ connection wasn't using a proxy. This caused NTLM authentication
+ failures when using proxies as the authentication code wasn't send on
+ the connection where the challenge arrived.
+
+ Added test 1215 to verify: NTLM server authentication through a proxy
+ (This is a modified copy of test 67)
+
+- RELEASE-NOTES: sync with 704a5dfca9
+
+- TODO-RELEASE: cleaned up, not really maintained lately
+
+Marc Hoersken (7 Apr 2013)
+- if2ip.c: Fixed another warning: unused parameter 'remote_scope'
+
+Daniel Stenberg (7 Apr 2013)
+- [Marc Hoersken brought this change]
+
+ cookie.c: Made cookie sort function more deterministic
+
+ Since qsort implementations vary with regards to handling the order
+ of similiar elements, this change makes the internal sort function
+ more deterministic by comparing path length first, then domain length
+ and finally the cookie name. Spotted with testcase 62 on Windows.
+
+Marc Hoersken (7 Apr 2013)
+- curl_schannel.c: Follow up on memory leak fix ae4558d
+
+- Revert "getpart.pm: Strip carriage returns to fix Windows support"
+
+ This reverts commit e51b23c925a2721cf7c29b2b376d3d8903cfb067.
+ As discussed on the mailinglist, this was not the correct approach.
+
+- http_negotiate.c: Fixed passing argument from incompatible pointer type
+
+- ftp.c: Added missing brackets around ABOR command logic
+
+- sockfilt.c: Fixed detection of client-side connection close
+
+ WINSOCK only:
+ Since FD_CLOSE is only signaled once, it may trigger at the same
+ time as FD_READ. Data actually being available makes it impossible
+ to detect that the connection was closed by checking that recv returns
+ zero. Another recv attempt could block the connection if it was
+ not closed. This workaround abuses exceptfds in conjunction with
+ readfds to signal that the connection has actually closed.
+
+- curl_schannel.c: Fixed memory leak if connection was not successful
+
+- if2ip.c: Fixed warning: unused parameter 'remote_scope'
+
+- runtests.pl: Fixed --verbose parameter passed to http_pipe.py
+
+- sockfilt.c: Reduce CPU load while running under a Windows PIPE
+
+- tftpd.c: Apply sread timeout to the whole data transfer session
+
+- getpart.pm: Strip carriage returns to fix Windows support
+
+Daniel Stenberg (6 Apr 2013)
+- ftp tests: libcurl returns CURLE_FTP_ACCEPT_FAILED better now
+
+ Since commit 57aeabcc1a20f, it handles errors on the control connection
+ while waiting for the data connection better.
+
+ Test 591 and 592 are updated accordingly.
+
+- FTP: wait on both connections during active STOR state
+
+ When doing PORT and upload (STOR), this function needs to extract the
+ file descriptor for both connections so that it will respond immediately
+ when the server eventually connects back.
+
+ This flaw caused active connections to become unnecessary slow but they
+ would still often work due to the normal polling on a timeout. The bug
+ also would not occur if the server connected back very fast, like when
+ testing on local networks.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1183
+ Reported by: Daniel Theron
+
+Marc Hoersken (6 Apr 2013)
+- tftpd.c: Follow up cleanup and restore of previous sockopt
+
+Daniel Stenberg (6 Apr 2013)
+- [Kim Vandry brought this change]
+
+ connect: treat an interface bindlocal() problem as a non-fatal error
+
+ I am using curl_easy_setopt(CURLOPT_INTERFACE, "if!something") to force
+ transfers to use a particular interface but the transfer fails with
+ CURLE_INTERFACE_FAILED, "Failed binding local connection end" if the
+ interface I specify has no IPv6 address. The cause is as follows:
+
+ The remote hostname resolves successfully and has an IPv6 address and an
+ IPv4 address.
+
+ cURL attempts to connect to the IPv6 address first.
+
+ bindlocal (in lib/connect.c) fails because Curl_if2ip cannot find an
+ IPv6 address on the interface.
+
+ This is a fatal error in singleipconnect()
+
+ This change will make cURL try the next IP address in the list.
+
+ Also included are two changes related to IPv6 address scope:
+
+ - Filter the choice of address in Curl_if2ip to only consider addresses
+ with the same scope ID as the connection address (mismatched scope for
+ local and remote address does not result in a working connection).
+
+ - bindlocal was ignoring the scope ID of addresses returned by
+ Curl_if2ip . Now it uses them.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1189
+
+Marc Hoersken (6 Apr 2013)
+- tftpd.c: Fixed sread timeout on Windows by setting it manually
+
+- ftp.pm: Added tskill to support Windows XP Home
+
+- runtests.pl: Modularization of MinGW/Msys compatibility functions
+
+- ftp.pm: Made Perl testsuite able to handle Windows processes
+
+- util.c: Revert workaround eeefcdf, 6eb56e7 and e3787e8
+
+- ftp.pm: Made Perl testsuite able to kill Windows processes
+
+- util.c: Follow up cleanup on eeefcdf
+
+Daniel Stenberg (6 Apr 2013)
+- cpp: use #ifdef __MINGW32__ to avoid compiler complaints
+
+ ... instead of just #if
+
+Marc Hoersken (6 Apr 2013)
+- util.c: Made write_pidfile write the correct PID on MinGW/Msys
+
+ This workaround fixes an issue on MinGW/Msys regarding the Perl
+ testsuite scripts not being able to signal or control the server
+ processes. The MinGW Perl runtime only sees the Msys processes and
+ their corresponding PIDs, but sockfilt (and other servers) wrote the
+ Windows PID into their PID-files. Since this PID is useless to the
+ testsuite, the write_pidfile function was changed to search for the
+ Msys PID and write that into the PID-file.
+
+Daniel Stenberg (5 Apr 2013)
+- RELEASE-NOTES: synced with 5e722b2d09087
+
+ 3 more bug fixes, 6 more contributors
+
+Marc Hoersken (5 Apr 2013)
+- sockfilt.c: Fixed handling of multiple fds being signaled
+
+Kamil Dudka (5 Apr 2013)
+- curl_global_init.3: improve description of CURL_GLOBAL_ALL
+
+ Reported by: Tomas Mlcoch
+
+- examples/multi-single.c: fix the order of destructions
+
+ ... so that it adheres to the API documentation.
+
+ Reported by: Tomas Mlcoch
+
+Daniel Stenberg (5 Apr 2013)
+- Curl_open: restore default MAXCONNECTS to 5
+
+ At some point recently we lost the default value for the easy handle's
+ connection cache, and this change puts it back to 5 - which is the
+ former default value and it is documented in the curl_easy_setopt.3 man
+ page.
+
+Marc Hoersken (4 Apr 2013)
+- sockfilt.c: Added wrapper functions to fix Windows console issues
+
+ The new read and write wrapper functions support reading from stdin
+ and writing to stdout/stderr on Windows by using the appropriate
+ Windows API functions and data types.
+
+Yang Tse (4 Apr 2013)
+- lib1509.c: fix compiler warnings
+
+- easy.c: fix compiler warning
+
+Daniel Stenberg (4 Apr 2013)
+- --engine: spellfix the help message
+
+ Reported by: Fredrik Thulin
+
+Yang Tse (4 Apr 2013)
+- http_negotiate.c: follow-up for commit 3dcc1a9c
+
+Linus Nielsen Feltzing (4 Apr 2013)
+- easy: Fix the broken CURLOPT_MAXCONNECTS option
+
+ Copy the CURLOPT_MAXCONNECTS option to CURLMOPT_MAXCONNECTS in
+ curl_easy_perform().
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1212
+ Reported-by: Steven Gu
+
+Guenter Knauf (4 Apr 2013)
+- Updated copyright date.
+
+- Another small output fix for --help and --version.
+
+Yang Tse (4 Apr 2013)
+- http_negotiate.c: fix several SPNEGO memory handling issues
+
+Guenter Knauf (4 Apr 2013)
+- Added a cont to specify base64 line wrap.
+
+- Fixed version output.
+
+- Added support for --help and --version options.
+
+- Added option to specify length of base64 output.
+
+ Based on a patch posted to the list by Richard Michael.
+
+Daniel Stenberg (3 Apr 2013)
+- curl_easy_setopt.3: CURLOPT_HTTPGET disables CURLOPT_UPLOAD
+
+- [Yasuharu Yamada brought this change]
+
+ Curl_cookie_add: only increase numcookies for new cookies
+
+ Count up numcookies in Curl_cookie_add() only when cookie is new one
+
+- SO_SNDBUF: don't set SNDBUF for win32 versions vista or later
+
+ The Microsoft knowledge-base article
+ http://support.microsoft.com/kb/823764 describes how to use SNDBUF to
+ overcome a performance shortcoming in winsock, but it doesn't apply to
+ Windows Vista and later versions. If the described SNDBUF magic is
+ applied when running on those more recent Windows versions, it seems to
+ instead have the reversed effect in many cases and thus make libcurl
+ perform less good on those systems.
+
+ This fix thus adds a run-time version-check that does the SNDBUF magic
+ conditionally depending if it is deemed necessary or not.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1188
+ Reported by: Andrew Kurushin
+ Tested by: Christian Hägele
+
+Nick Zitzmann (1 Apr 2013)
+- darwinssl: additional descriptive messages of SSL handshake errors
+
+ (This doesn't need to appear in the release notes.)
+
+Guenter Knauf (1 Apr 2013)
+- Added dns and connect time to output.
+
+Daniel Stenberg (1 Apr 2013)
+- RELEASE-NOTES: synced with 0614b902136
+
+- code-policed
+
+- tcpkeepalive: support TCP_KEEPIDLE/TCP_KEEPINTVL on win32
+
+ Patch by: Robert Wruck
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1209
+
+- BINDINGS: BBHTTP is a cocoa binding, Julia has a binding
+
+- ftp_sendquote: use PPSENDF, not FTPSENDF
+
+ The last remaining code piece that still used FTPSENDF now uses PPSENDF.
+ In the problematic case, a PREQUOTE series was done on a re-used
+ connection when Curl_pp_init() hadn't been called so it had messed up
+ pointers. The init call is done properly from Curl_pp_sendf() so this
+ change fixes this particular crash.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-03/0319.html
+ Reported by: Sam Deane
+
+Steve Holme (27 Mar 2013)
+- RELEASE-NOTES: Corrected typo
+
+Daniel Stenberg (27 Mar 2013)
+- [Clemens Gruber brought this change]
+
+ multi-uv.c: remove unused variable
+
+- RELEASE-NOTES: add two references
+
+- test1509: verify proxy header response headers count
+
+ Modified sws to support and use custom CONNECT responses instead of the
+ previously naive hard-coded version. Made the HTTP test server able to
+ extract test case number from the host name in a CONNECT request by
+ finding the number after the last dot. It makes 'machine.moo.123' use
+ test case 123.
+
+ Adapted a larger amount of tests to the new <connect> style.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1204
+ Reported by: Martin Jansen
+
+- [Clemens Gruber brought this change]
+
+ Added libuv example multi-uv.c
+
+Yang Tse (25 Mar 2013)
+- NTLM: fix several NTLM code paths memory leaks
+
+- WIN32 MemoryTracking: track wcsdup() _wcsdup() and _tcsdup() usage
+
+ As of 25-mar-2013 wcsdup() _wcsdup() and _tcsdup() are only used in
+ WIN32 specific code, so tracking of these has not been extended for
+ other build targets. Without this fix, memory tracking system on
+ WIN32 builds, when using these functions, would provide misleading
+ results.
+
+ In order to properly extend this support for all targets curl.h
+ would have to define curl_wcsdup_callback prototype and consequently
+ wchar_t should be visible before that in curl.h. IOW curl_wchar_t
+ defined in curlbuild.h and this pulling whatever system header is
+ required to get wchar_t definition.
+
+ Additionally a new curl_global_init_mem() function that also receives
+ user defined wcsdup() callback would be required.
+
+- curl_ntlm_msgs.c: revert commit 463082bea4
+
+ reverts unreleased invalid memory leak fix
+
+Daniel Stenberg (23 Mar 2013)
+- RELEASE-NOTES: synced with bc6037ed3ec02
+
+ More changes, bugfixes and contributors!
+
+- [Martin Jansen brought this change]
+
+ Curl_proxyCONNECT: count received headers
+
+ Proxy servers tend to add their own headers at the beginning of
+ responses. The size of these headers was not taken into account by
+ CURLINFO_HEADER_SIZE before this change.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1204
+
+Steve Holme (21 Mar 2013)
+- sasl: Corrected a few violations of the curl coding standards
+
+ Corrected some incorrectly positioned pointer variable declarations to
+ be "char *" rather than "char* ".
+
+- multi.c: Corrected a couple of violations of the curl coding standards
+
+ Corrected some incorrectly positioned pointer variable declarations to
+ be "type *" rather than "type* ".
+
+- imap-tests: Added CRLF to reply data to be compliant with RFC-822
+
+ Updated the reply data in tests: 800, 801, 802, 804 and 1321 to possess
+ the CRLF as per RFC-822.
+
+- multi.c: Fix compilation warning
+
+ warning: an enumerated type is mixed with another type
+
+- multi.c: fix compilation error
+
+ warning: conversion from enumeration type to different enumeration type
+
+- lib1900.c: fix compilation warning
+
+ warning: declaration of 'time' shadows a global declaration
+
+Yang Tse (20 Mar 2013)
+- [John E. Malmberg brought this change]
+
+ build_vms.com: use existing curlbuild.h and parsing fix
+
+ This patch removes building curlbuild.h from the build_vms.com procedure
+ and uses the one in the daily or release tarball instead.
+
+ packages/vms/build_curlbuild_h.com is obsolete with this change.
+
+ Accessing the library module name "tool_main" needs different handling
+ when the optional extended parsing is enabled.
+
+ Tested on IA64/VMS 8.4 and VAX/VMS 7.3
+
+Nick Zitzmann (19 Mar 2013)
+- darwinssl: disable ECC ciphers under Mountain Lion by default
+
+ I found out that ECC doesn't work as of OS X 10.8.3, so those ciphers are
+ turned off until the next point release of OS X.
+
+Steve Holme (18 Mar 2013)
+- FEATURES: Small tidy up for constancy and grammar
+
+Daniel Stenberg (18 Mar 2013)
+- [Oliver Schindler brought this change]
+
+ Curl_proxyCONNECT: clear 'rewindaftersend' on success
+
+ After having done a POST over a CONNECT request, the 'rewindaftersend'
+ boolean could be holding the previous value which could lead to badness.
+
+ This should be tested for in a new test case!
+
+ Bug: https://groups.google.com/d/msg/msysgit/B31LNftR4BI/KhRTz0iuGmUJ
+
+Steve Holme (18 Mar 2013)
+- TODO: Reordered the protocol and security sections
+
+ Moved SMTP, POP3, IMAP and New Protocol sections to be listed after the
+ other protocols (FTP, HTTP and TELNET) and SASL to be after SSL and
+ GnuTLS as these are all security related.
+
+ Additionally fixed numbering of the SSL and GnuTLS sections as they
+ weren't consecutive.
+
+Yang Tse (18 Mar 2013)
+- tests: specify 'text' mode for some output files in verify section
+
+Steve Holme (17 Mar 2013)
+- imap: Fixed incorrect initial response generation for SASL AUTHENTICATE
+
+ Fixed incorrect initial response generation for the NTLM and LOGIN SASL
+ authentication mechanisms when the SASL-IR was detected.
+
+ Introduced in commit: 6da7dc026c14.
+
+- FEATURES: Expanded the supported enhanced IMAP command list
+
+- TODO: Corrected typo in TOC
+
+- TODO: Added IMAP section and removed unused Other protocols section
+
+- TODO: Added graceful base64 decoding failure to SMTP and POP3
+
+- TODO: Corrected typo on section 10.2 heading
+
+Yang Tse (16 Mar 2013)
+- tests: 96, 558, 1330: strip build subdirectory dependent leading path
+
+Steve Holme (15 Mar 2013)
+- TODO: Added section 10.2 Initial response to POP3 to do list
+
+- imap-tests: Corrected copy/paste error in test808 reply data
+
+Yang Tse (15 Mar 2013)
+- unit1330.c: fix date
+
+- tests: add #96 #558 and #1330
+
+ These verfy that the 'memory tracking' subsystem is actually doing its
+ job when using curl tool (#96), a test in libtest (#558) and also a unit
+ test (#1330), in order to prevent regressions in this functionallity.
+
+Steve Holme (15 Mar 2013)
+- imap-tests: Added test808 for custom EXAMINE command
+
+Daniel Stenberg (15 Mar 2013)
+- HTTP proxy: insert slash in URL if missing
+
+ curl has been accepting URLs using slightly wrong syntax for a long
+ time, such as when completely missing as slash "http://example.org" or
+ missing a slash when a query part is given
+ "http://example.org?q=foobar".
+
+ curl would translate these into a legitimate HTTP request to servers,
+ although as was shown in bug #1206 it was not adjusted properly in the
+ cases where a HTTP proxy was used.
+
+ Test 1213 and 1214 were added to the test suite to verify this fix.
+
+ The test HTTP server was adjusted to allow us to specify test number in
+ the host name only without using any slashes in a given URL.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1206
+ Reported by: ScottJi
+
+Steve Holme (14 Mar 2013)
+- ftpserver.pl: Added EXAMINE_imap() for IMAP EXAMINE commands
+
+ Used hard coded data from RFC-3501 section 6.3.2.
+
+Yang Tse (14 Mar 2013)
+- curl_memory.h: introduce CURLX_NO_MEMORY_CALLBACKS usage possibility
+
+ This commit alone does not fix anything nor modifies existing
+ interfaces or behaviors, although it is a prerequisite for other
+ fixes.
+
+- Makefile.vc6: add missing files
+
+Linus Nielsen Feltzing (14 Mar 2013)
+- pipelining: Remove dead code.
+
+- Multiple pipelines and limiting the number of connections.
+
+ Introducing a number of options to the multi interface that
+ allows for multiple pipelines to the same host, in order to
+ optimize the balance between the penalty for opening new
+ connections and the potential pipelining latency.
+
+ Two new options for limiting the number of connections:
+
+ CURLMOPT_MAX_HOST_CONNECTIONS - Limits the number of running connections
+ to the same host. When adding a handle that exceeds this limit,
+ that handle will be put in a pending state until another handle is
+ finished, so we can reuse the connection.
+
+ CURLMOPT_MAX_TOTAL_CONNECTIONS - Limits the number of connections in total.
+ When adding a handle that exceeds this limit,
+ that handle will be put in a pending state until another handle is
+ finished. The free connection will then be reused, if possible, or
+ closed if the pending handle can't reuse it.
+
+ Several new options for pipelining:
+
+ CURLMOPT_MAX_PIPELINE_LENGTH - Limits the pipeling length. If a
+ pipeline is "full" when a connection is to be reused, a new connection
+ will be opened if the CURLMOPT_MAX_xxx_CONNECTIONS limits allow it.
+ If not, the handle will be put in a pending state until a connection is
+ ready (either free or a pipe got shorter).
+
+ CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE - A pipelined connection will not
+ be reused if it is currently processing a transfer with a content
+ length that is larger than this.
+
+ CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE - A pipelined connection will not
+ be reused if it is currently processing a chunk larger than this.
+
+ CURLMOPT_PIPELINING_SITE_BL - A blacklist of hosts that don't allow
+ pipelining.
+
+ CURLMOPT_PIPELINING_SERVER_BL - A blacklist of server types that don't allow
+ pipelining.
+
+ See the curl_multi_setopt() man page for details.
+
+Yang Tse (13 Mar 2013)
+- tool_main.c: remove redundant vms_show storage-class specifier
+
+ vms_show 'extern' storage-class specifier removed from tool_main.c due to...
+
+ - Advice from Tor Arntsen: http://curl.haxx.se/mail/lib-2013-03/0164.html
+
+ - HP OpenVMS docs stating that 'Extern is the default storage class for
+ variables declared outside a function.'
+ http://h71000.www7.hp.com/commercial/c/docs/dec_c_help_5.html
+ (Storage_Classes section)
+
+- test509: libcurl initialization with memory callbacks and actual usage
+
+Steve Holme (13 Mar 2013)
+- pop3: Removed unnecessary transfer cancellation
+
+ Following commit e450f66a02d8 and the changes in the multi interface
+ being used internally, from 7.29.0, the transfer cancellation in
+ pop3_dophase_done() is no longer required.
+
+Yang Tse (13 Mar 2013)
+- Makefile.am: add VMS files not being included in tarball
+
+- [Tom Grace brought this change]
+
+ build_vms.com: VMS build fixes
+
+ Added missing slash in cc_full_list.
+ Removed unwanted extra quotes inside symbol tool_main
+ for non-VAX architectures that triggered link failure.
+ Replaced curl_sys_inc with sys_inc.
+
+- [Tom Grace brought this change]
+
+ tool_main.c: fix VMS global variable storage-class specifier
+
+ An extern submits a psect and a global reference to the linker to point
+ to it. Using "extern int vms_show = 0" also creates a globaldef.
+
+ The use of the extern by itself does declare a psect but does not declare
+ a globalsymbol. It does declare a globalref. But the linker needs one and
+ only one globaldef or there is an error.
+
+Patrick Monnerat (12 Mar 2013)
+- OS400: synchronize RPG binding
+
+Steve Holme (12 Mar 2013)
+- pop3: Fixed continuous wait when using --ftp-list
+
+ Don't initiate a transfer when using --ftp-list.
+
+Kamil Dudka (12 Mar 2013)
+- [Zdenek Pavlas brought this change]
+
+ curl_global_init: accept the CURL_GLOBAL_ACK_EINTR flag
+
+ The flag can be used in pycurl-based applications where using the multi
+ interface would not be acceptable because of the performance lost caused
+ by implementing the select() loop in python.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1168
+ Downstream Bug: https://bugzilla.redhat.com/919127
+
+- easy: do not ignore poll() failures other than EINTR
+
+Yang Tse (12 Mar 2013)
+- curl.h: stricter CURL_EXTERN linkage decorations logic
+
+ No API change involved.
+
+ Info: http://curl.haxx.se/mail/lib-2013-02/0234.html
+
+Daniel Stenberg (11 Mar 2013)
+- THANKS: Latin-1'ified Jiri's name
+
+Steve Holme (11 Mar 2013)
+- test806: Added CRLF to reply data to be compliant with RFC-822
+
+Daniel Stenberg (11 Mar 2013)
+- test805: added crlf newlines to make data size match
+
+ since mails sent are supposed to have CRLF line endings I added them and
+ now the data size after (\Seen) matches again properly
+
+- test: fix newline for the data check of 807
+
+Yang Tse (11 Mar 2013)
+- test801 to test807: fix protocol section line endings
+
+Steve Holme (10 Mar 2013)
+- Makefile.am: Corrected a couple of spurious tab characters
+
+ Corrected a couple of tab characters between test702 and test703, and
+ between test900 and test901 which should be spaces.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test807 for custom request functionality (STORE)
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test806 for IMAP (folder) LIST command
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test805 for APPEND functionality
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test804 for skipping SELECT if in the same mailbox
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test802 and test803 for UIDVALIDITY verification
+
+ Added one test for a request with matching UIDVALIDITY and one which is
+ a mismatched request that will fail.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added test801 for UID and SECTION URL parameters
+
+- [Jiri Hruska brought this change]
+
+ imap-tests: Accept quoted parameters in ftpserver.pl
+
+ Any IMAP parameter can come in escaped and in double quotes. Added a
+ simple function to unquote the command parameters and applied it to
+ the IMAP command handlers.
+
+- [Jiri Hruska brought this change]
+
+ tests: Fix ftpserver.pl indentation
+
+ The whole of FETCH_imap() had one extra space of indentation, whilst
+ APPEND_imap() used indentation of 2 instead of 4 in places.
+
+- Makefile.am: Corrected end of line filler character
+
+ The majority of lines, that specify a test file for inclusion, end with
+ a tab character before the slash whilst some end with a space. Corrected
+ those that end with a space to end with a tab character as well.
+
+- email-tests: Updated the test data that corresponds to the test number
+
+ Finished segregating the email protocol tests, into their own protocol
+ based ranges, in preparation of adding more e-mail related tests to the
+ test suite.
+
+- email-tests: Renamed the IMAP test to be 800
+
+ Continued segregating the email protocol tests, into their own protocol
+ based ranges, in preparation of adding more e-mail related tests to the
+ test suite.
+
+- email-tests: Renamed the SMTP tests to be in the range 900-906
+
+ Continued segregating the email protocol tests, into their own protocol
+ based ranges, in preparation of adding more e-mail related tests to the
+ test suite.
+
+- email-tests: Renamed the POP3 tests to be in the range 850-857
+
+ Started segregating the email protocol tests, into their own protocol
+ based ranges, in preparation of adding more e-mail related tests to the
+ test suite.
+
+Daniel Stenberg (10 Mar 2013)
+- hiperfifo: updated to use current libevent API
+
+ Patch by: Myk Taylor
+
+Steve Holme (10 Mar 2013)
+- imap: Reworked some function descriptions
+
+- imap: Added some missing comments to imap_sendf()
+
+- email: Removed hard returns from init functions
+
+Daniel Stenberg (9 Mar 2013)
+- curl_multi_wait: avoid second loop if nothing to do
+
+ ... hopefully this will also make clang-analyzer stop warning on
+ potentional NULL dereferences (which were false positives anyway).
+
+- multi_runsingle: avoid NULL dereference
+
+ When Curl_do() returns failure, the connection pointer could be NULL so
+ the code path following needs to that that into account.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-03/0062.html
+ Reported by: Eric Hu
+
+Steve Holme (9 Mar 2013)
+- imap: Re-factored all perform based functions
+
+ Standardised the naming of all perform based functions to be in the form
+ imap_perform_something().
+
+Daniel Stenberg (9 Mar 2013)
+- [Cédric Deltheil brought this change]
+
+ examples/getinmemory.c: abort the transfer if not enough memory
+
+ No more use exit(3) but instead tell libcurl that no byte has been
+ written to let it return a `CURLE_WRITE_ERROR`. In addition, check
+ curl easy handle return code.
+
+- RELEASE-NOTES: synced with ca3c0ed3a9c
+
+ 8 more bugfixes, one change and a bunch of contributors
+
+Yang Tse (9 Mar 2013)
+- Makefile.am: empty AM_LDFLAGS definition for automake 1.7 compatibility
+
+Steve Holme (9 Mar 2013)
+- imap: Added description comments to all perform based functions
+
+- imap: Removed the need for separate custom request functions
+
+ Moved the custom request processing into the LIST command as the logic
+ is the same.
+
+- imap: Corrected typo in comment
+
+Yang Tse (9 Mar 2013)
+- Makefile.am: empty AM_LDFLAGS definition for automake 1.7 compatibility
+
+Steve Holme (9 Mar 2013)
+- imap: Moved imap_logout() to be grouped with the other perform functions
+
+- email: Updated the function descriptions for the logout / quit functions
+
+ Updated the function description comments following commit 4838d196fdbf.
+
+- email: Simplified the logout / quit functions
+
+ Moved the blocking state machine to the disconnect functions so that the
+ logout / quit functions are only responsible for sending the actual
+ command needed to logout or quit.
+
+ Additionally removed the hard return on failure.
+
+- email: Tidied up the *_regular_transfer() functions
+
+ Added comments and simplified convoluted dophase_done comparison.
+
+- email: Simplified nesting of if statements in *_doing() functions
+
+Daniel Stenberg (8 Mar 2013)
+- RELEASE-NOTES: mention that krb4 is up for consideration
+
+Steve Holme (8 Mar 2013)
+- imap: Fixed handling of untagged responses for the STORE custom command
+
+ Added an exception, for the STORE command, to the untagged response
+ processor in imap_endofresp() as servers will back respones containing
+ the FETCH keyword instead.
+
+Yang Tse (8 Mar 2013)
+- curlbuild.h.dist: enhance non-configure GCC ABI detection logic
+
+ GCC specific adjustments:
+
+ - check __ILP32__ before 32 and 64bit processor architectures in
+ order to detect ILP32 programming model on 64 bit processors
+ which, of course, also support LP64 programming model, when using
+ gcc 4.7 or newer.
+
+ - keep 32bit processor architecture checks in order to support gcc
+ versions older than 4.7 which don't define __ILP32__
+
+ - check __LP64__ for gcc 3.3 and newer, while keeping 64bit processor
+ architecture checks for older versions which don't define __LP64__
+
+- curlbuild.h.dist: fix GCC build on ARM systems without configure script
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1205
+ Reported by: technion
+
+- [Gisle Vanem brought this change]
+
+ polarssl.c: fix header filename typo
+
+- configure: use XC_LIBTOOL for portability across libtool versions
+
+- xc-lt-iface.m4: provide XC_LIBTOOL macro
+
+Steve Holme (7 Mar 2013)
+- imap: Fixed SELECT not being performed for custom requests
+
+- email: Minor code tidy up following recent changes
+
+ Removed unwanted braces and added variable initialisation.
+
+- DOCS: Corrected the IMAP URL grammar of the UIDVALIDITY parameter
+
+- FEATURES: Provided a little clarity in some IMAP features
+
+- email: Optimised block_statemach() functions
+
+ Optimised the result test in each of the block_statemach() functions.
+
+- DOCS: Added the list command to the IMAP URL section
+
+ Added examples of the list command and clarified existing example URLs
+ following recent changes.
+
+- FEATURES: Updated for recent imap additions
+
+ Updated the imap features list, corrected a typo in the smtp features
+ and clarified a pop3 feature.
+
+Daniel Stenberg (7 Mar 2013)
+- version bump: the next release will be 7.30.0
+
+- checksrc: ban unsafe functions
+
+ The list of unsafe functions currently consists of sprintf, vsprintf,
+ strcat, strncat and gets.
+
+ Subsequently, some existing code needed updating to avoid warnings on
+ this.
+
+Steve Holme (7 Mar 2013)
+- RELEASE-NOTES: Added missing imap fixes and additions
+
+ With all the recent imap changes it wasn't clear what new features and
+ fixes should be included in the release notes.
+
+Nick Zitzmann (6 Mar 2013)
+- RELEASE-NOTES: brought this up-to-date with the latest changes
+
+Steve Holme (6 Mar 2013)
+- [Jiri Hruska brought this change]
+
+ imap: Fixed test801 and test1321 to specify a message UID
+
+ Just a folder list would be retrieved if UID was not specified now.
+
+- [Jiri Hruska brought this change]
+
+ imap: Fixed ftpserver.pl to allow verification even through LIST command
+
+ Commit 198012ee inadvertently broke LIST_imap().
+
+- imap: Tidied up the APPEND and final APPEND response functions
+
+ Removed unnecessary state changes on failure and setting of result codes
+ on success.
+
+- imap: Tidied up the final FETCH response function
+
+ Removed unnecessary state change on failure and setting of result code on
+ success.
+
+- imap: Tidied up the LIST response function
+
+ Reworked comments as they referenced custom commands, removed
+ unnecessary state change on failure and setting of result code on
+ success.
+
+- imap: Removed the custom request response function
+
+ Removed imap_state_custom_resp() as imap_state_list_resp() provides the
+ same functionality.
+
+- [Jiri Hruska brought this change]
+
+ imap: Updated ftpserver.pl to be more compliant, added new commands
+
+ Enriched IMAP capabilities of ftpserver.pl in order to be able to
+ add tests for the new IMAP features.
+
+ * Added support for APPEND - Saves uploaded data to log/upload.$testno
+ * Added support for LIST - Returns the contents of <reply/> section in
+ the current test, like e.g FETCH.
+ * Added support for STORE - Returns hardcoded updated flags
+ * Changed handling of SELECT - Returns much more information in the
+ usual set of untagged responses; uses hardcoded data from an example
+ in the IMAP RFC
+ * Changed handling of FETCH - Fixed response format
+
+- imap: Added check for empty UID in FETCH command
+
+ As the UID has to be specified by the user for the FETCH command to work
+ correctly, added a check to imap_fetch(), although strictly speaking it
+ is protected by the call from imap_perform().
+
+Kamil Dudka (6 Mar 2013)
+- nss: fix misplaced code enabling non-blocking socket mode
+
+ The option needs to be set on the SSL socket. Setting it on the model
+ takes no effect. Note that the non-blocking mode is still not enabled
+ for the handshake because the code is not yet ready for that.
+
+Daniel Stenberg (6 Mar 2013)
+- imap: fix compiler warning
+
+ imap.c:694:21: error: unused variable 'imapc' [-Werror=unused-variable]
+
+Steve Holme (5 Mar 2013)
+- imap: Added support for list command
+
+- imap: Added list perform and response handler functions
+
+- imap: Introduced IMAP_LIST state
+
+- imap: Small tidy up of imap_select() to match imap_append()
+
+ Updated the style of imap_select() before adding the LIST command.
+
+- imap: Moved mailbox check from the imap_do() function
+
+ In preparation for the addition of the LIST command, moved the mailbox
+ check from imap_do() to imap_select() and imap_append().
+
+- curl_setup.h: Added S_IRDIR() macro for compilers that don't support it
+
+ Commit 26eaa8383001 introduces the use of S_ISDIR() yet some compilers,
+ such as MSVC don't support it, so we must define a substitute using
+ file flags and mask.
+
+Daniel Stenberg (4 Mar 2013)
+- AddFormData: prevent only directories from being posted
+
+ Commit f4cc54cb4746ae5a6d (shipped as part of the 7.29.0 release) was a
+ bug fix that introduced a regression in that while trying to avoid
+ allowing directory names, it also forbade "special" files like character
+ devices and more. like "/dev/null" as was used by Oliver who reported
+ this regression.
+
+ Reported by: Oliver Gondža
+ Bug: http://curl.haxx.se/mail/archive-2013-02/0040.html
+
+Nick Zitzmann (3 Mar 2013)
+- darwinssl: fix infinite loop if server disconnected abruptly
+
+ If the server hung up the connection without sending a closure alert,
+ then we'd keep probing the socket for data even though it's dead. Now
+ we're ready for this situation.
+
+ Bug: http://curl.haxx.se/mail/lib-2013-03/0014.html
+ Reported by: Aki Koskinen
+
+Steve Holme (3 Mar 2013)
+- imap: Added comments to imap_append()
+
+- [Jiri Hruska brought this change]
+
+ imap: Added required mailbox check for FETCH and APPEND commands
+
+- pingpong.c: Fix enumerated type mixed with another type
+
+- smtp: Updated the coding style for state changes after a send operation
+
+ Some state changes would be performed after a failure test that
+ performed a hard return, whilst others would be performed within a test
+ for success. Updated the code, for consistency, so all instances are
+ performed within a success test.
+
+- pop3: Updated the coding style for state changes after a send operation
+
+ Some state changes would be performed after a failure test that
+ performed a hard return, whilst others would be performed within a test
+ for success. Updated the code, for consistency, so all instances are
+ performed within a success test.
+
+- imap: Fixed typo in variable assignment
+
+- [Jiri Hruska brought this change]
+
+ imap: Fixed custom request handling in imap_done()
+
+ Fixed imap_done() so that neither the FINAL states are not entered when
+ a custom command has been performed.
+
+- [Jiri Hruska brought this change]
+
+ imap: Enabled custom requests in imap_select_resp()
+
+ Changed imap_select_resp() to invoke imap_custom() instead of
+ imap_fetch() after the mailbox has been selected if a custom
+ command has been set.
+
+- [Jiri Hruska brought this change]
+
+ imap: Enabled custom requests in imap_perform()
+
+ Modified imap_perform() to start with the custom command instead of
+ SELECT when a custom command is to be performed and no mailbox has
+ been given.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added custom request perform and response handler functions
+
+ Added imap_custom(), which initiates the custom command processing,
+ and an associated response handler imap_state_custom_resp(), which
+ handles any responses by sending them to the client as body data.
+
+ All untagged responses with the same name as the first word of the
+ custom request string are accepted, with the exception of SELECT and
+ EXAMINE which have responses that cannot be easily identified. An
+ extra check has been provided for them so that any untagged responses
+ are accepted for them.
+
+- pop3: Fixed unnecessary parent structure reference
+
+ Updated pop3 code following recent imap changes.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added custom request parsing
+
+ Added imap_parse_custom_request() for parsing the CURLOPT_CUSTOMREQUEST
+ parameter which URL decodes the value and separates the request from
+ any parameters - This makes it easier to filter untagged responses
+ by the request command.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced custom request parameters
+
+ Added custom request parameters to the per-request structure.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced IMAP_CUSTOM state
+
+- imap: Minor code tidy up
+
+ Minor tidy up of code layout and comments following recent changes.
+
+- imap: Simplified the imap_state_append_resp() function
+
+ Introduced the result code variable to simplify the state changes and
+ remove the hard returns.
+
+- imap: Changed successful response logic in imap_state_append_resp()
+
+ For consistency changed the logic of the imap_state_append_resp()
+ function to test for an unsucessful continuation response rather than a
+ succesful one.
+
+- imap: Standardised imapcode condition tests
+
+ For consistency changed two if(constant != imapcode) tests to be
+ if(imapcode != constant).
+
+- imap: Moved imap_append() to be with the other perform functions
+
+- [Jiri Hruska brought this change]
+
+ imap: Enabled APPEND support in imap_perform()
+
+ Added logic in imap_perform() to perform an APPEND rather than SELECT
+ and FETCH if an upload has been specified.
+
+- [Jiri Hruska brought this change]
+
+ imap: Implemented APPEND final processing
+
+ The APPEND operation needs to be performed in several steps:
+ 1) We send "<tag> APPEND <mailbox> <flags> {<size>}\r\n"
+ 2) Server responds with continuation respose "+ ...\r\n"
+ 3) We start the transfer and send <size> bytes of data
+ 4) Only now we end the request command line by sending "\r\n"
+ 5) Server responds with "<tag> OK ...\r\n"
+
+ This commit performs steps 4 and 5, in the DONE phase, as more
+ processing is required after the transfer.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added APPEND perform and response handler functions
+
+ Added imap_append() function to initiate upload and imap_append_resp()
+ to handle the continuation response and start the transfer.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced IMAP_APPEND and IMAP_APPEND_FINAL states
+
+- [Jiri Hruska brought this change]
+
+ imap: Updated setting of transfer variables in imap_state_fetch_resp()
+
+ Add number of bytes retrieved from the PP cache to req.bytecount and set
+ req.maxdownload only when starting a proper download.
+
+- [Jiri Hruska brought this change]
+
+ imap: Improved FETCH response parsing
+
+ Added safer parsing of the untagged FETCH response line and the size of
+ continuation data.
+
+- imap: Fixed accidentally lossing the result code
+
+ Accidentally lost the result code in imap_state_capability() and
+ imap_state_login() with commit b06a78622609.
+
+- imap: Another minor comment addition / tidy up
+
+- imap: Updated the coding style for state changes after a send operation
+
+ Some state changes would be performed after a failure test that
+ performed a hard return, whilst others would be performed within a test
+ for success. Updated the code, for consistency, so all instances are
+ performed within a success test.
+
+- pop3 / smtp: Small comment tidy up
+
+ Small tidy up to keep some comments consistant across each of the email
+ protocols.
+
+- [Jiri Hruska brought this change]
+
+ imap: FETCH response handler cleanup before further changes
+
+ Removed superfluous NULL assignment after Curl_safefree() and rewrote
+ some comments and logging messages.
+
+- pop3: Small tidy up of function arguments
+
+- imap: Small tidy up of function arguments
+
+- smtp: Corrected debug message for POP3_AUTH_FINAL constant
+
+ Following commit ad3177da24b8 corrected the debug message in state()
+ from AUTH to AUTH_FINAL.
+
+- pop3: Corrected debug message for POP3_AUTH_FINAL constant
+
+ Following commit afad1ce753a1 corrected the debug message in state()
+ from AUTH to AUTH_FINAL.
+
+- imap: Corrected debug message for IMAP_AUTHENTICATE_FINAL constant
+
+ Following commit 13006f3de9ec corrected the debug message in state()
+ from AUTHENTICATE to AUTHENTICATE_FINAL.
+
+- [Jiri Hruska brought this change]
+
+ imap: Fixed error code returned for invalid FETCH response
+
+ If the FETCH command does not result in an untagged response the the
+ UID is probably invalid. As such do not return CURLE_OK.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added processing of the final FETCH responses
+
+ Not processing the final FETCH responses was not optimal, not only
+ because the response code would be ignored but it would also leave data
+ unread on the socket which would prohibit connection reuse.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced FETCH_FINAL state for processing final fetch responses
+
+ A typical FETCH response can be broken down into four parts:
+
+ 1) "* <uid> FETCH (<what> {<size>}\r\n", using continuation syntax
+ 2) <size> bytes of the actual message
+ 3) ")\r\n", finishing the untagged response
+ 4) "<tag> OK ...", finishing the command
+
+ Part 1 is read in imap_fetch_resp(), part 2 is consumed in the PERFORM
+ phase by the transfer subsystem, parts 3 and 4 are currently ignored.
+
+- imap: fix autobuild warning
+
+ Removed whitespace from imap_perform()
+
+- imap: fix compiler warning
+
+ error: declaration of 'imap' shadows a previous local
+
+- smtp: Re-factored the final SMTP_AUTH constant
+
+ Changed the final SMTP_AUTH constant to SMTP_AUTH_FINAL for consistency
+ with the response function.
+
+- pop3: Re-factored the final POP3_AUTH constant
+
+ Changed the final POP3_AUTH constant to POP3_AUTH_FINAL for consistency
+ with the response function.
+
+- imap: Re-factored final IMAP_AUTHENTICATE constant
+
+ Changed the final IMAP_AUTHENTICATE constant to IMAP_AUTHENTICATE_FINAL
+ for consistency with the response function.
+
+- imap: Updated the coding style of imap_state_servergreet_resp()
+
+ Updated the coding style, in this function, to be consistant with other
+ response functions rather then performing a hard return on failure.
+
+- imap: Reversed the logic of the (un)successful tagged SELECT response
+
+ Reversed the logic of the unsuccessful vs successful tagged SELECT
+ response in imap_state_select_resp() to be more logical to read.
+
+- imap: Reversed the logic of the (un)successful tagged CAPABILITY response
+
+ Reversed the logic of the unsuccessful vs successful tagged CAPABILITY
+ response in imap_state_capability_resp() to be more logical to read.
+
+- imap: Corrected char* references with char *
+
+ Corrected char* references made in commit: 709b3506cd9b.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added processing of more than one response when sent in same packet
+
+ Added a loop to imap_statemach_act() in which Curl_pp_readresp() is
+ called until the cache is drained. Without this multiple responses
+ received in a single packet could result in a hang or delay.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added skipping of SELECT command if already in the same mailbox
+
+ Added storage and checking of the last mailbox userd to prevent
+ unnecessary switching.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced the mailbox variable
+
+ Added the mailbox variable to the per-connection structure in
+ preparation for checking for an already selected mailbox.
+
+- email: Slight reordering of connection based variables
+
+ Reordered the state and ssl_done variables in order to provide more
+ consistency between the email protocols as well as for for an upcoming
+ change.
+
+- imap: Tidied up comments for connection based variables
+
+- DOCS: Added the IMAP UIDVALIDITY property to the CURLOPT_URL section
+
+- [Jiri Hruska brought this change]
+
+ imap: Added verification of UIDVALIDITY mailbox attribute
+
+ Added support for checking the UIDVALIDITY, and aborting the request, if
+ it has been specified in the URL and the server response is different.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added support for parsing the UIDVALIDITY property
+
+ Added support for parsing the UIDVALIDITY property from the SELECT
+ response and storing it in the per-connection structure.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced the mailbox_uidvalidity variable
+
+ Added the mailbox_uidvalidity variable to the per-connection structure
+ in preparation for checking the UIDVALIDITY mailbox attribute.
+
+- imap: Corrected comment in imap_endofresp()
+
+- imap: Corrected whitespace
+
+- [Jiri Hruska brought this change]
+
+ imap: Added filtering of CAPABILITY and FETCH untagged responses
+
+ Only responses that contain "CAPABILITY" and "FETCH", respectively,
+ will be sent to their response handler.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added a helper function for upcoming untagged response filtering
+
+ RFC 3501 states that "the client MUST be prepared to accept any response
+ at all times" yet we assume anything received with "* " at the beginning
+ is the untagged response we want.
+
+ Introduced a helper function that checks whether the input looks like a
+ response to specified command, so that we may filter the ones we are
+ interested in according to the current state.
+
+- [Jiri Hruska brought this change]
+
+ imap: Moved CAPABILITY response handling to imap_state_capability_resp()
+
+ Introduced similar handling to the FETCH responses, where even the
+ untagged data responses are handled by the response handler of the
+ individual state.
+
+Linus Nielsen Feltzing (26 Feb 2013)
+- Remove unused variable in smtp_state_data_resp()
+
+Steve Holme (25 Feb 2013)
+- email: Small tidy up following recent changes
+
+- smtp: Removed bytecountp from the per-request structure
+
+ Removed this pointer to a downloaded bytes counter because it was set in
+ smtp_init() to point to the same variable the transfer functions keep
+ the count in (k->bytecount), effectively making the code in transfer.c
+ "*k->bytecountp = k->bytecount" a no-op.
+
+- pop3: Removed bytecountp from the per-request structure
+
+ Removed this pointer to a downloaded bytes counter because it was set in
+ pop3_init() to point to the same variable the transfer functions keep
+ the count in (k->bytecount), effectively making the code in transfer.c
+ "*k->bytecountp = k->bytecount" a no-op.
+
+- [Jiri Hruska brought this change]
+
+ imap: Removed bytecountp from the per-request structure
+
+ Removed this pointer to a downloaded bytes counter because it was set in
+ imap_init() to point to the same variable the transfer functions keep
+ the count in (k->bytecount), effectively making the code in transfer.c
+ "*k->bytecountp = k->bytecount" a no-op.
+
+- [Jiri Hruska brought this change]
+
+ imap: Adjusted SELECT and FETCH function order
+
+ Moved imap_select() and imap_fetch() to be grouped with the other
+ perform functions.
+
+- [Jiri Hruska brought this change]
+
+ imap: Adjusted SELECT and FETCH state order in imap_statemach_act()
+
+ Exchanged the position of these states in the switch statements to
+ match the state enum, execution and function order.
+
+- imap: Minor tidy up of comments in imap_parse_url_path()
+
+ Tidy up of comments before next round of imap changes.
+
+- imap: Fixed incorrect comparison for STARTTLS in imap_endofresp()
+
+ Corrected the comparison type in addition to commit 1dac29fa83a9.
+
+- DOCS: Corrected IMAP URL examples according to RFC5092
+
+ URL examples that included the UID weren't technically correct although
+ would pass the curl parser.
+
+Nick Zitzmann (24 Feb 2013)
+- darwinssl: fix undefined $ssllib warning in runtests.pl
+
+ I also added --with-darwinssl to the list of SSL options in configure.
+
+Steve Holme (24 Feb 2013)
+- imap: Added check for new internal imap response code
+
+- imap: Changed the order of the response types in imap_endofresp()
+
+ From a maintenance point of view the code reads better to view tagged
+ responses, then untagged followed by continuation responses.
+
+ Additionally, this matches the order of responses in POP3.
+
+- [Jiri Hruska brought this change]
+
+ imap: Added stricter parsing of continuation responses
+
+ Enhanced the parsing to only allow continuation responses in some
+ states.
+
+- imap: Simplified memcmp() in tagged response parsing
+
+- [Jiri Hruska brought this change]
+
+ imap: Reworked the logic of untagged command responses
+
+- imap: Corrected spacing of trailing brace
+
+- [Jiri Hruska brought this change]
+
+ imap: Added stricter parsing of tagged command responses
+
+ Enhanced the parsing of tagged responses which must start with "OK",
+ "NO" or "BAD"
+
+- [Jiri Hruska brought this change]
+
+ imap: Simplified command response test in imap_endofresp()
+
+- [Jiri Hruska brought this change]
+
+ imap: Corrected comment in imap_endofresp()
+
+- DOCS: Corrected layout of POP3 and IMAP URL examples
+
+ Corrected layout issues with the POP3 and IMAP URL examples introduced
+ in commit cb3ae6894fb2.
+
+- DOCS: Updated CURLOPT_URL section following recent POP3 and IMAP changes
+
+ Updated the POP3 sub-section to refer to message ID rather than mailbox.
+
+ Added an IMAP sub-section with example URLs depicting the specification
+ of mailbox, uid and section.
+
+- pop3: Refactored the mailbox variable as it didn't reflect it's purpose
+
+ Updated the mailbox variable to correctly reflect it's purpose. The
+ name mailbox was a leftover from when IMAP and POP3 support was
+ initially added to curl.
+
+- FEATURES: Updated following recent IMAP changes
+
+- [Jiri Hruska brought this change]
+
+ imap: Added the ability to FETCH a specific UID and SECTION
+
+ Updated the FETCH command to send the UID and SECTION parsed from the
+ URL. By default the BODY specifier doesn't include a section, BODY[] is
+ now sent whereas BODY[TEXT] was previously sent. In my opinion
+ retrieving just the message text is rarely useful when dealing with
+ emails, as the headers are required for example, so that functionality
+ is not retained. In can however be simulated by adding SECTION=TEXT to
+ the URL.
+
+ Also updated test801 and test1321 due to the BODY change.
+
+- email: Additional tidy up of comments following recent changes
+
+- smtp: Removed some FTP heritage leftovers
+
+ Removed user and passwd from the SMTP struct as these cannot be set on
+ a per-request basis and are leftover from legacy FTP code.
+
+ Changed some comments still using FTP terminology.
+
+- smtp: Moved the per-request variables to the per-request data structure
+
+ Moved the rcpt variable from the per-connection struct smtp_conn to the
+ new per-request struct and fixed references accordingly.
+
+- pop3: Introduced a custom SMTP structure for per-request data
+
+ Created a new SMTP structure and changed the type of the smtp proto
+ variable in connectdata from FTP* to SMTP*.
+
+unknown (23 Feb 2013)
+- [Steve Holme brought this change]
+
+ imap: Minor correction of comments for max line length
+
+Daniel Stenberg (23 Feb 2013)
+- strcasestr: remove check for this unused function
+
+- pop3: fix compiler warning
+
+ error: declaration of 'pop3' shadows a previous local
+
+Steve Holme (23 Feb 2013)
+- [Jiri Hruska brought this change]
+
+ imap: Added URL parsing of new variables
+
+ Updated the imap_parse_url_path() function to parse uidvalidity, uid and
+ section parameters based on RFC-5092.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced imap_is_bchar() function
+
+ Added imap_is_bchar() for testing if a given character is a valid bchar
+ or not.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced new per-request veriables
+
+ Added uidvalidity, uid and section variables to the per-request IMAP
+ structure in preparation for upcoming URL parsing.
+
+- pingpong: Renamed curl_ftptransfer to curl_pp_transfer
+
+- pop3: Removed some FTP heritage leftovers
+
+ Removed user and passwd from the POP3 struct as these cannot be set on
+ a per-request basis and are leftover from legacy FTP code.
+
+ Changed some comments still using FTP terminology.
+
+- pop3: Moved the per-request variables to the per-request data structure
+
+ Moved the mailbox and custom request variables from the per-connection
+ struct pop3_conn to the new per-request struct and fixed references
+ accordingly.
+
+- pop3: Introduced a custom POP3 structure for per-request data
+
+ Created a new POP3 structure and changed the type of the pop3 proto
+ variable in connectdata from FTP* to POP*.
+
+- [Jiri Hruska brought this change]
+
+ imap: Fixed escaping of mailbox names
+
+ Used imap_atom() to escape mailbox names in imap_select().
+
+- pingpong: Moved curl_ftptransfer definition to pingpong.h
+
+ Moved the ftp transfer structure into pingpong.h so other protocols that
+ require it don't have to include ftp.h.
+
+- urldata.h: Fixed comment for opt_no_body variable
+
+ Corrected comment for opt_no_body variable to CURLOPT_NOBODY.
+
+- email: Minor tidy up following IMAP changes
+
+- [Jiri Hruska brought this change]
+
+ imap: Removed more FTP leftovers
+
+ Changed some variables and comments still using FTP terminology.
+
+- [Jiri Hruska brought this change]
+
+ imap: Removed some FTP heritage leftovers
+
+ Removed user and passwd from the IMAP struct as these cannot be set on
+ a per-request basis and are leftover from legacy FTP code.
+
+- [Jiri Hruska brought this change]
+
+ imap: Introduced a custom IMAP structure for per-request data
+
+ Created a new IMAP structure and changed the type of the imap proto
+ variable in connectdata from FTP* to the new IMAP*.
+
+ Moved the mailbox variable from the per-connection struct imap_conn to
+ the new per-request struct and fixed references accordingly.
+
+- pop3: Updated do phrase clean-up comment
+
+ Following commit 65644b833532 for the IMAP module updated the clean-up
+ comment in POP3.
+
+- imap: Fixed memory leak when performing multiple selects
+
+ Moved the clean-up of the mailbox variable from imap_disconnect() to
+ imap_done() as this variable is allocated in the do phase, yet would
+ have only been freed only once if multiple selects where preformed
+ on a single connection.
+
+Daniel Stenberg (22 Feb 2013)
+- [Alexander Klauer brought this change]
+
+ Documentation: Typo in docs/CONTRIBUTE
+
+ Fixes a typo get → git in docs/CONTRIBUTE.
+
+- [Alexander Klauer brought this change]
+
+ repository: ignore patch files generated by git
+
+ Ignores the patch files generated by the 'git format-patch' command.
+
+- [Alexander Klauer brought this change]
+
+ libcurl documentation: clarifications and typos
+
+ * Elaborates on default values of some curl_easy_setopt() options.
+ * Reminds the user to cast variadic arguments to curl_easy_setopt() to
+ 'void *' where curl internally interprets them as such.
+ * Clarifies the working of the CURLOPT_SEEKFUNCTION option for
+ curl_easy_setopt().
+ * Fixes typo 'forth' → 'fourth'.
+ * Elaborates on CURL_SOCKET_TIMEOUT.
+ * Adds some missing periods.
+ * Notes that the return value of curl_version() must not be passed to
+ free().
+
+- [Alexander Klauer brought this change]
+
+ lib/url.c: Generic read/write data pointers
+
+ Always interprets the pointer passed with the CURLOPT_WRITEDATA or
+ CURLOPT_READDATA options of curl_easy_setopt() as a void pointer in
+ order to avoid problems in environments where FILE and void pointers
+ have non-trivial conversion.
+
+- [Alexander Klauer brought this change]
+
+ libcurl documentation: updates HTML index
+
+ * Adds several links to documentation of library functions which were
+ missing.
+ * Marks documentation of deprecated library functions "(deprecated)".
+ * Removes spurious .html suffixes.
+
+- ossl_seed: avoid recursive seeding!
+
+Steve Holme (22 Feb 2013)
+- [Jiri Hruska brought this change]
+
+ Fixed checking the socket if there is data waiting in the cache
+
+ Use Curl_pp_moredata() in Curl_pp_multi_statemach() to check if there is
+ more data to be received, rather than the socket state, as a task could
+ hang waiting for more data from the socket itself.
+
+- imap.c: Fixed an incorrect variable reference
+
+ Fixed an incorrect variable reference which was introduced in commit
+ a1701eea289f as a result of a copy and paste from SMTP/POP3.
+
+- [Jiri Hruska brought this change]
+
+ pingpong: Introduce Curl_pp_moredata()
+
+ A simple function to test whether the PP is not sending and there are
+ still more data in its receiver cache. This will be later utilized to:
+
+ 1) Change Curl_pp_multi_statemach() and Curl_pp_easy_statemach() to
+ not test socket state and just call user's statemach_act() function
+ when there are more data to process, because otherwise the task would
+ just hang, waiting for more data from the socket.
+
+ 2) Allow PP users to read multiple responses by looping as long as there
+ are more data available and current phase is not finished.
+ (Currently needed for correct processing of IMAP SELECT responses.)
+
+Nick Zitzmann (19 Feb 2013)
+- FEATURES: why yes, we do support metalink
+
+ I just noticed Metalink support wasn't listed as a feature of the tool.
+
+- metalink: fix improbable crash parsing metalink filename
+
+ The this_url pointer wasn't being initialized, so if strdup() would return
+ null when copying the filename in a metalink file, then hilarity would
+ ensue during the cleanup phase. This change was brought to you by clang,
+ which noticed this and raised a warning.
+
+Yang Tse (19 Feb 2013)
+- smtp.c: fix enumerated type mixed with another type
+
+- polarssl threadlock cleanup
+
+Nick Zitzmann (18 Feb 2013)
+- docs: schannel and darwinssl documentation improvements
+
+ Schannel and darwinssl use the certificates built into the
+ OS to do vert verification instead of bundles. darwinssl
+ is thread-safe. Corrected typos in the NSS docs.
+
+Daniel Stenberg (18 Feb 2013)
+- resolver_error: remove wrong error message output
+
+ The attempt to use gai_strerror() or alternative function didn't work as
+ the 'sock_error' field didn't contain the proper error code. But since
+ this hasn't been reported and thus isn't really a big deal I decided to
+ just scrap the whole attempt to output the detailed resolver error and
+ instead remain with just stating that the resolving of the name failed.
+
+- [Kim Vandry brought this change]
+
+ Curl_resolver_is_resolved: show proper host name on failed resolve
+
+- Curl_resolver_is_resolved: fix compiler warning
+
+ conversion to 'int' from 'long int' may alter its value
+
+- compiler warning fix
+
+ follow-up to commit ed7174c6f66, rename 'wait' to 'block'
+
+- compiler warning fix: declaration of 'wait' shadows a global declaration
+
+ It seems older gcc installations (at least) will cause warnings if we
+ name a variable 'wait'. Now changed to 'block' instead.
+
+ Reported by: Jiří Hruška
+ Bug: http://curl.haxx.se/mail/lib-2013-02/0247.html
+
+Nick Zitzmann (17 Feb 2013)
+- MacOSX-Framework: Make script work in Xcode 4.0 and later
+
+ Apple made a number of changes to Xcode 4. The SDKs were moved, the entire
+ Developer folder was moved, and PowerPC support was removed. The script
+ will now adapt to those changes and should be future-proofed against
+ additional changes in case Apple moves the Developer folder ever again.
+ Also, the minimum OS X version compiler option was removed, so that the
+ framework can be built against the latest SDK but still run in older cats.
+
+Daniel Stenberg (17 Feb 2013)
+- docs: refer to CURLOPT_ACCEPT_ENCODING instead of the old name
+
+Steve Holme (16 Feb 2013)
+- email: Tidied up result code variables
+
+ Tidied up result variables to be consistent in name, declaration order
+ and default values.
+
+Nick Zitzmann (16 Feb 2013)
+- ntlm_core: fix compiler warning when building with clang
+
+ Fixed a 64-to-32 compiler warning raised when building with
+ clang and the --with-darwinssl option.
+
+Daniel Stenberg (16 Feb 2013)
+- Guile-curl: a new libcurl binding
+
+- polarsslthreadlock: #include the proper memory and debug includes
+
+ Pointed out by Steve Holme
+
+Steve Holme (16 Feb 2013)
+- email: Removed unnecessary forward declaration
+
+ Due to the reordering of functions in commit 586f5d361474 the forward
+ declaration to state_upgrade_tls() are no longer required.
+
+- pop3.c: Added reference to RFC-5034
+
+Daniel Stenberg (15 Feb 2013)
+- [Willem Sparreboom brought this change]
+
+ PolarSSL: Change to cURL coding style
+
+ Repaired all curl/lib/checksrc.pl warnings in the previous four patches
+
+- [Willem Sparreboom brought this change]
+
+ PolarSSL: WIN32 threading support for entropy
+
+ Added WIN32 threading support for PolarSSL entropy if
+ --enable-threaded-resolver config flag is set and process.h can be found.
+
+- [Willem Sparreboom brought this change]
+
+ PolarSSL: pthread support for entropy
+
+ Added pthread support for polarssl entropy if --enable-threaded-resolver
+ config flag is set and pthread.h can be found.
+
+- [Willem Sparreboom brought this change]
+
+ PolarSSL: changes to entropy/ctr_drbg/HAVEGE_RANDOM
+
+ Add non-threaded entropy and ctr_drbg and removed HAVEGE_RANDOM define
+
+- [Willem Sparreboom brought this change]
+
+ PolarSSL: added human readable error strings
+
+ Print out human readable error strings for PolarSSL related errors
+
+Steve Holme (15 Feb 2013)
+- pop3: Removed unnecessary state changes on failure
+
+- imap: Removed unnecessary state change on failure
+
+Daniel Stenberg (15 Feb 2013)
+- metalink_cleanup: yet another follow-up fix
+
+- metalink_cleanup: define it without argument
+
+ Since the function takes no argument, the macro shouldn't take one as
+ some compilers will error out on that.
+
+- rename "easy" statemachines: call them block instead
+
+ ... since they're not used by the easy interface really, I wanted to
+ remove the association. Also, I unified the pingpong statemachine driver
+ into a single function with a 'wait' argument: Curl_pp_statemach.
+
+Yang Tse (15 Feb 2013)
+- [Gisle Vanem brought this change]
+
+ curl_setup_once.h: definition of HAVE_CLOSE_S defines sclose() to close_s()
+
+- [Gisle Vanem brought this change]
+
+ config-dos.h: define HAVE_CLOSE_S for MSDOS/Watt-32
+
+- [Gisle Vanem brought this change]
+
+ config-dos.h: define strerror() to strerror_s_() for High-C
+
+- [Gisle Vanem brought this change]
+
+ config-dos.h: define HAVE_TERMIOS_H only for djgpp
+
+Steve Holme (14 Feb 2013)
+- smtp.c: Fixed a trailing whitespace
+
+ Remove tailing whitespace introduced in commit 7ed689d24a4e.
+
+- pop3: Fixed blocking SSL connect when connecting via POP3S
+
+ A call to Curl_ssl_connect() was accidentally left in when the SSL/TLS
+ connection layer was reworked in 7.29. Not only would this cause the
+ connection to block but had the additional overhead of calling the
+ non-blocking connect a little bit later.
+
+- smtp: Refactored the smtp_state_auth_resp() function
+
+ Renamed smtp_state_auth_resp() function to match the implementations in
+ IMAP and POP3.
+
+Daniel Stenberg (14 Feb 2013)
+- remove ifdefs
+
+ Clarify the code by reducing ifdefs
+
+- strlcat: remove function
+
+ This function was only used twice, both in places where performance
+ isn't crucial (socks + if2ip). Removing the use of this function removes
+ the need to have our private version for systems without it == reduced
+ amount of code.
+
+ Also, in the SOCKS case it is clearly better to fail gracefully rather
+ than to truncate the results.
+
+ This work was triggered by a bug report on the strcal prototype in
+ strequal.h.
+
+ strlcat was added in commit db70cd28 in February 2001!
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1192
+ Reported by: Jeremy Huddleston
+
+- Curl_FormBoundary: made static
+
+ As Curl_FormBoundary() is no longer used outside of this file (since
+ commit ad7291c1a9d), it is now renamed to formboundary() and is made
+ static.
+
+- ossl_seed: fix the last resort PRNG seeding
+
+ Instead of just abusing the pseudo-randomizer from Curl_FormBoundary(),
+ this now uses Curl_ossl_random() to get entropy.
+
+Steve Holme (13 Feb 2013)
+- email: Tidy up before additional IMAP work
+
+ Replaced two explicit comparisons of CURLE_OK with boolean alternatives.
+
+ General tidy up of comments.
+
+- smtp: Removed duplicate pingpong structure initialisation
+
+ The smtp_connect() function was setting the member variables of the
+ pingpong structure twice, once before calling Curl_pp_init() and once
+ after!
+
+Yang Tse (13 Feb 2013)
+- move msvc IDE related files to 'vs' directory tree
+
+ Use 'vs' directory tree given that 'vc' intended one clashes
+ with an already existing build target in file Makefile.dist.
+
+Daniel Stenberg (13 Feb 2013)
+- install-sh: updated to support multiple source files as arguments
+
+ Version 7.29.0 uses Makefiles generated with a newer version of the
+ autotools than the previous 7.28.1. These Makefiles try to install
+ e.g. header files by calling install-sh with multiple source files as
+ arguments. The bundled install-sh is to old and does not support this.
+
+ The problem only occurs, if install-sh is actually being used, ie. the
+ platform install executable is to old or not usable. Example: Solaris
+ 10.
+
+ The files install-sh and mkinstalldirs are now updated with the automake
+ 1.11.3 versions. A better fix might be to completely remove them from
+ git and force the files to be added/created during buildconf.
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1195
+ Reported by: Rainer Jung
+
+Yang Tse (13 Feb 2013)
+- move msvc IDE related files to 'vc' directory tree
+
+- msvc IDE 'vc' directory tree preparation
+
+Steve Holme (12 Feb 2013)
+- imap: Corrected a whitespace issue from previous commit
+
+ Fixed a small whitespace issue that crept in there in commit
+ 508cdf4da4d7.
+
+- email: Another post optimisation of endofresp() tidy up
+
+- sasl: Fixed null pointer reference when decoding empty digest challenge
+
+ Fixed a null pointer reference when an empty challenge is passed to the
+ Curl_sasl_create_digest_md5_message() function.
+
+ Bug: http://sourceforge.net/p/curl/bugs/1193/
+ Reported by: Saran Neti
+
+- email: Post optimisation of endofresp() tidy up
+
+ Removed unnecessary end of line check and return.
+
+Nick Zitzmann (12 Feb 2013)
+- darwinssl: Fix send glitchiness with data > 32 or so KB
+
+ An ambiguity in the SSLWrite() documentation lead to a bad inference in the
+ code where we assumed SSLWrite() returned the amount of bytes written to
+ the socket, when that is not actually true; it returns the amount of data
+ that is buffered for writing to the socket if it returns errSSLWouldBlock.
+ Now darwinssl_send() returns CURLE_AGAIN if data is buffered but not written.
+
+ Reference URL: http://curl.haxx.se/mail/lib-2013-02/0145.html
+
+Steve Holme (12 Feb 2013)
+- pingpong.h: Fixed line length over 78 characters from b56c9eb48e3c
+
+- pingpong: Optimised the endofresp() function
+
+ Reworked the pp->endofresp() function so that the conndata, line and
+ line length are passed down to it just as with Curl_client_write()
+ rather than each implementation of the function having to query
+ these values.
+
+ Additionally changed the int return type to bool as this is more
+ representative of the function's usage.
+
+- email: Post STARTLS capability code tidy up (Part Three)
+
+ Corrected the order of the upgrade_tls() functions and moved the handler
+ upgrade and getsock() functions out from the middle of the state related
+ functions.
+
+- email: Post STARTLS capability code tidy up (Part Two)
+
+ Corrected the order of the pop3_state_capa() / imap_state_capability()
+ and the pop3_state_capa_resp() / imap_state_capability_resp() functions
+ to match the execution order.
+
+Daniel Stenberg (11 Feb 2013)
+- [ulion brought this change]
+
+ SOCKS: fix socks proxy when noproxy matched
+
+ Test 1212 added to verify
+
+ Bug: http://curl.haxx.se/bug/view.cgi?id=1190
+
+Steve Holme (11 Feb 2013)
+- ntlm: Updated comments for the addition of SASL support to IMAP in v7.29
+
+- RELEASE-NOTES: Updated following the recent imap/pop3/smtp changes
+
+Linus Nielsen Feltzing (10 Feb 2013)
+- Fix NULL pointer reference when closing an unused multi handle.
+
+Steve Holme (10 Feb 2013)
+- email: Post STARTLS capability code tidy up (Part One)
+
+ Corrected the order of the CAPA / CAPABILITY state machine constants to
+ match the execution order.
+
+- imap: Fixed memory leak following commit f6010d9a0359
+
+- smtp: Added support for the STARTTLS capability (Part Two)
+
+ Added honoring of the tls_supported flag when starting a TLS upgrade
+ rather than unconditionally attempting it. If the use_ssl flag is set
+ to CURLUSESSL_TRY and the server doesn't support TLS upgrades then the
+ connection will continue to authenticate. If this flag is set to
+ CURLUSESSL_ALL then the connection will complete with a failure as it
+ did previously.
+
+- pop3: Added support for the STLS capability (Part Three)
+
+ Added honoring of the tls_supported flag when starting a TLS upgrade
+ rather than unconditionally attempting it. If the use_ssl flag is set
+ to CURLUSESSL_TRY and the server doesn't support TLS upgrades then the
+ connection will continue to authenticate. If this flag is set to
+ CURLUSESSL_ALL then the connection will complete with a failure as it
+ did previously.
+
+- imap: Added support for the STARTTLS capability (Part Three)
+
+ Added honoring of the tls_supported flag when starting a TLS upgrade
+ rather than unconditionally attempting it. If the use_ssl flag is set
+ to CURLUSESSL_TRY and the server doesn't support TLS upgrades then the
+ connection will continue to authenticate. If this flag is set to
+ CURLUSESSL_ALL then the connection will complete with a failure as it
+ did previously.
+
+Daniel Stenberg (10 Feb 2013)
+- [Alessandro Ghedini brought this change]
+
+ htmltitle: fix suggested build command
+
+Steve Holme (10 Feb 2013)
+- pop3: Added support for the STLS capability (Part Two)
+
+ Added sending of initial CAPA command before STLS is sent. This allows
+ for the detection of the capability before trying to upgrade the
+ connection.
+
+- imap: Added support for the STARTTLS capability (Part Two)
+
+ Added sending of initial CAPABILITY command before STARTTLS is sent.
+ This allows for the detection of the capability before trying to
+ upgrade the connection.
+
+- smtp: Added support for the STLS capability (Part One)
+
+ Introduced detection of the STARTTLS capability, in order to add support
+ for TLS upgrades without unconditionally sending the STARTTLS command.
+
+- pop3: Added support for the STLS capability (Part One)
+
+ Introduced detection of the STLS capability, in order to add support
+ for TLS upgrades without unconditionally sending the STLS command.
+
+- imap: Added support for the STARTTLS capability (Part One)
+
+ Introduced detection of the STARTTLS capability, in order to add support
+ for TLS upgrades without unconditionally sending the STARTTLS command.
diff --git a/libs/libcurl/docs/CONTRIBUTE b/libs/libcurl/docs/CONTRIBUTE
new file mode 100644
index 0000000000..75e7ebbb93
--- /dev/null
+++ b/libs/libcurl/docs/CONTRIBUTE
@@ -0,0 +1,310 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ When Contributing Source Code
+
+ This document is intended to offer guidelines that can be useful to keep in
+ mind when you decide to contribute to the project. This concerns new features
+ as well as corrections to existing flaws or bugs.
+
+ 1. Learning cURL
+ 1.1 Join the Community
+ 1.2 License
+ 1.3 What To Read
+
+ 2. cURL Coding Standards
+ 2.1 Naming
+ 2.2 Indenting
+ 2.3 Commenting
+ 2.4 Line Lengths
+ 2.5 General Style
+ 2.6 Non-clobbering All Over
+ 2.7 Platform Dependent Code
+ 2.8 Write Separate Patches
+ 2.9 Patch Against Recent Sources
+ 2.10 Document
+ 2.11 Test Cases
+
+ 3. Pushing Out Your Changes
+ 3.1 Write Access to git Repository
+ 3.2 How To Make a Patch with git
+ 3.3 How To Make a Patch without git
+ 3.4 How to get your changes into the main sources
+ 3.5 Write good commit messages
+ 3.6 Please don't send pull requests
+
+==============================================================================
+
+1. Learning cURL
+
+1.1 Join the Community
+
+ Skip over to http://curl.haxx.se/mail/ and join the appropriate mailing
+ list(s). Read up on details before you post questions. Read this file before
+ you start sending patches! We prefer patches and discussions being held on
+ the mailing list(s), not sent to individuals.
+
+ Before posting to one of the curl mailing lists, please read up on the mailing
+ list etiquette: http://curl.haxx.se/mail/etiquette.html
+
+ We also hang out on IRC in #curl on irc.freenode.net
+
+1.2. License
+
+ When contributing with code, you agree to put your changes and new code under
+ the same license curl and libcurl is already using unless stated and agreed
+ otherwise.
+
+ If you add a larger piece of code, you can opt to make that file or set of
+ files to use a different license as long as they don't enforce any changes to
+ the rest of the package and they make sense. Such "separate parts" can not be
+ GPL licensed (as we don't want copyleft to affect users of libcurl) but they
+ must use "GPL compatible" licenses (as we want to allow users to use libcurl
+ properly in GPL licensed environments).
+
+ When changing existing source code, you do not alter the copyright of the
+ original file(s). The copyright will still be owned by the original
+ creator(s) or those who have been assigned copyright by the original
+ author(s).
+
+ By submitting a patch to the curl project, you are assumed to have the right
+ to the code and to be allowed by your employer or whatever to hand over that
+ patch/code to us. We will credit you for your changes as far as possible, to
+ give credit but also to keep a trace back to who made what changes. Please
+ always provide us with your full real name when contributing!
+
+1.3 What To Read
+
+ Source code, the man pages, the INTERNALS document, TODO, KNOWN_BUGS, the
+ 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
+
+2.1 Naming
+
+ Try using a non-confusing naming scheme for your new functions and variable
+ names. It doesn't necessarily have to mean that you should use the same as in
+ other places of the code, just that the names should be logical,
+ understandable and be named according to what they're used for. File-local
+ functions should be made static. We like lower case names.
+
+ See the INTERNALS document on how we name non-exported library-global
+ symbols.
+
+2.2 Indenting
+
+ 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.
+
+2.3 Commenting
+
+ Comment your source code extensively using C comments (/* comment */), DO NOT
+ use C++ comments (// this style). Commented code is quality code and enables
+ future modifications much more. Uncommented code risk having to be completely
+ replaced when someone wants to extend things, since other persons' source
+ code can get quite hard to read.
+
+2.4 Line Lengths
+
+ We write source lines shorter than 80 columns.
+
+2.5 General Style
+
+ Keep your functions small. If they're small you avoid a lot of mistakes and
+ you don't accidentally mix up variables etc.
+
+2.6 Non-clobbering All Over
+
+ When you write new functionality or fix bugs, it is important that you don't
+ fiddle all over the source files and functions. Remember that it is likely
+ that other people have done changes in the same source files as you have and
+ possibly even in the same functions. If you bring completely new
+ functionality, try writing it in a new source file. If you fix bugs, try to
+ fix one bug at a time and send them as separate patches.
+
+2.7 Platform Dependent Code
+
+ Use #ifdef HAVE_FEATURE to do conditional code. We avoid checking for
+ particular operating systems or hardware in the #ifdef lines. The
+ HAVE_FEATURE shall be generated by the configure script for unix-like systems
+ and they are hard-coded in the config-[system].h files for the others.
+
+2.8 Write Separate Patches
+
+ It is annoying when you get a huge patch from someone that is said to fix 511
+ odd problems, but discussions and opinions don't agree with 510 of them - or
+ 509 of them were already fixed in a different way. Then the patcher needs to
+ extract the single interesting patch from somewhere within the huge pile of
+ source, and that gives a lot of extra work. Preferably, all fixes that
+ correct different problems should be in their own patch with an attached
+ 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
+ against. It makes the life of the developers so much easier. The very best is
+ if you get the most up-to-date sources from the git repository, but the
+ latest release archive is quite OK as well!
+
+2.10 Document
+
+ Writing docs is dead boring and one of the big problems with many open source
+ projects. Someone's gotta do it. It makes it a lot easier if you submit a
+ small description of your fix or your new features with every contribution so
+ that it can be swiftly added to the package documentation.
+
+ The documentation is always made in man pages (nroff formatted) or plain
+ ASCII files. All HTML files on the web site and in the release archives are
+ generated from the nroff/ASCII versions.
+
+2.11 Test Cases
+
+ Since the introduction of the test suite, we can quickly verify that the main
+ features are working as they're supposed to. To maintain this situation and
+ improve it, all new features and functions that are added need to be tested
+ in the test suite. Every feature that is added should get at least one valid
+ 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
+
+ If you are a frequent contributor, or have another good reason, you can of
+ course get write access to the git repository and then you'll be able to push
+ your changes straight into the git repo instead of sending changes by mail as
+ patches. Just ask if this is what you'd want. You will be required to have
+ posted a few quality patches first, before you can be granted push access.
+
+3.2 How To Make a Patch with git
+
+ You need to first checkout the repository:
+
+ git clone git://github.com/bagder/curl.git
+
+ You then proceed and edit all the files you like and you commit them to your
+ local repository:
+
+ git commit [file]
+
+ As usual, group your commits so that you commit all changes that at once that
+ constitutes a logical change. See also section "3.5 Write good commit
+ messages".
+
+ Once you have done all your commits and you're happy with what you see, you
+ can make patches out of your changes that are suitable for mailing:
+
+ git format-patch remotes/origin/master
+
+ This creates files in your local directory named NNNN-[name].patch for each
+ commit.
+
+ Now send those patches off to the curl-library list. You can of course opt to
+ do that with the 'git send-email' command.
+
+3.3 How To Make a Patch without git
+
+ Keep a copy of the unmodified curl sources. Make your changes in a separate
+ source tree. When you think you have something that you want to offer the
+ curl community, use GNU diff to generate patches.
+
+ If you have modified a single file, try something like:
+
+ diff -u unmodified-file.c my-changed-one.c > my-fixes.diff
+
+ If you have modified several files, possibly in different directories, you
+ can use diff recursively:
+
+ diff -ur curl-original-dir curl-modified-sources-dir > my-fixes.diff
+
+ The GNU diff and GNU patch tools exist for virtually all platforms, including
+ all kinds of Unixes and Windows:
+
+ For unix-like operating systems:
+
+ http://www.gnu.org/software/patch/patch.html
+ http://www.gnu.org/directory/diffutils.html
+
+ For Windows:
+
+ http://gnuwin32.sourceforge.net/packages/patch.htm
+ http://gnuwin32.sourceforge.net/packages/diffutils.htm
+
+3.4 How to get your changes into the main sources
+
+ Submit your patch to the curl-library mailing list.
+
+ Make the patch against as recent sources as possible.
+
+ Make sure your patch adheres to the source indent and coding style of already
+ existing source code. Failing to do so just adds more work for me.
+
+ Respond to replies on the list about the patch and answer questions and/or
+ fix nits/flaws. This is very important. I will take lack of replies as a sign
+ that you're not very anxious to get your patch accepted and I tend to simply
+ drop such patches from my TODO list.
+
+ If you've followed the above paragraphs and your patch still hasn't been
+ incorporated after some weeks, consider resubmitting it to the list.
+
+3.5 Write good commit messages
+
+ A short guide to how to do fine commit messages in the curl project.
+
+ ---- start ----
+ [area]: [short line describing the main effect]
+
+ [separate the above single line from the rest with an empty line]
+
+ [full description, no wider than 72 columns that describe as much as
+ possible as to why this change is made, and possibly what things
+ it fixes and everything else that is related]
+ ---- stop ----
+
+ Don't forget to use commit --author="" if you commit someone else's work,
+ and make sure that you have your own user and email setup correctly in git
+ before you commit
+
+3.6 Please don't send pull requests
+
+ With git (and especially github) it is easy and tempting to send a pull
+ request to one or more people in the curl project to have changes merged this
+ way instead of mailing patches to the curl-library mailing list.
+
+ We don't like that. We want them mailed for these reasons:
+
+ - Peer review. Anyone and everyone on the list can review, comment and
+ improve on the patch. Pull requests limit this ability.
+
+ - Anyone can merge the patch into their own trees for testing and those who
+ have push rights can push it to the main repo. It doesn't have to be anyone
+ the patch author knows beforehand.
+
+ - Commit messages can be tweaked and changed if merged locally instead of
+ using github. Merges directly on github requires the changes to be perfect
+ already, which they seldom are.
+
+ - Merges on github prevents rebases and even enforces --no-ff which is a git
+ style we don't otherwise use in the project
+
+ However: once patches have been reviewed and deemed fine on list they are
+ perfectly OK to be pulled from a published git tree.
diff --git a/libs/libcurl/docs/COPYING b/libs/libcurl/docs/COPYING
new file mode 100644
index 0000000000..85d122ecf0
--- /dev/null
+++ b/libs/libcurl/docs/COPYING
@@ -0,0 +1,21 @@
+COPYRIGHT AND PERMISSION NOTICE
+
+Copyright (c) 1996 - 2013, Daniel Stenberg, <daniel@haxx.se>.
+
+All rights reserved.
+
+Permission to use, copy, modify, and distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright
+notice and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
+NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
+OR OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall not
+be used in advertising or otherwise to promote the sale, use or other dealings
+in this Software without prior written authorization of the copyright holder.
diff --git a/libs/libcurl/docs/DISTRO-DILEMMA b/libs/libcurl/docs/DISTRO-DILEMMA
new file mode 100644
index 0000000000..108e6bad12
--- /dev/null
+++ b/libs/libcurl/docs/DISTRO-DILEMMA
@@ -0,0 +1,176 @@
+ Date: February 11, 2007
+ Author: Daniel Stenberg <daniel@haxx.se>
+ URL: http://curl.haxx.se/legal/distro-dilemma.html
+
+Condition
+
+ This document is written to describe the situation as it is right now.
+ libcurl 7.16.1 is currently the latest version available. Things may of
+ course change in the future.
+
+ This document reflects my view and understanding of these things. Please tell
+ me where and how you think I'm wrong, and I'll try to correct my mistakes.
+
+Background
+
+ The Free Software Foundation has deemed the Original BSD license[1] to be
+ "incompatible"[2] with GPL[3]. I'd rather say it is the other way around, but
+ the point is the same: if you distribute a binary version of a GPL program,
+ it MUST NOT be linked with any Original BSD-licensed parts or libraries.
+ Doing so will violate the GPL license. For a long time, very many GPL
+ licensed programs have avoided this license mess by adding an exception[8] to
+ their license. And many others have just closed their eyes for this problem.
+
+ libcurl is MIT-style[4] licensed - how on earth did this dilemma fall onto
+ our plates?
+
+ libcurl is only a little library. libcurl can be built to use OpenSSL for its
+ SSL/TLS capabilities. OpenSSL is basically Original BSD licensed[5].
+
+ If libcurl built to use OpenSSL is used by a GPL-licensed application and you
+ decide to distribute a binary version of it (Linux distros - for example -
+ tend to), you have a clash. GPL vs Original BSD.
+
+ This dilemma is not libcurl-specific nor is it specific to any particular
+ Linux distro. (This article mentions and refers to Debian several times, but
+ only because Debian seems to be the only Linux distro to have faced this
+ issue yet since no other distro is shipping libcurl built with two SSL
+ libraries.)
+
+Part of the Operating System
+
+ This would not be a problem if the used lib would be considered part of the
+ underlying operating system, as then the GPL license has an exception
+ clause[6] that allows applications to use such libs without having to be
+ allowed to distribute it or its sources. Possibly some distros will claim
+ that OpenSSL is part of their operating system.
+
+ Debian does however not take this stance and has officially(?) claimed that
+ OpenSSL is not a required part of the Debian operating system
+
+ Some people claim that this paragraph cannot be exploited this way by a Linux
+ distro, but I am not a lawyer and that is a discussion left outside of this
+ document.
+
+GnuTLS
+
+ Since May 2005 libcurl can get built to use GnuTLS instead of OpenSSL. GnuTLS
+ is an LGPL[7] licensed library that offers a matching set of features as
+ OpenSSL does. Now, you can build and distribute an TLS/SSL capable libcurl
+ without including any Original BSD licensed code.
+
+ I believe Debian is the first (only?) distro that provides libcurl/GnutTLS
+ packages.
+
+yassl
+
+ libcurl can get also get built to use yassl for the TLS/SSL layer. yassl is a
+ GPL[3] licensed library.
+
+
+GnuTLS vs OpenSSL vs yassl
+
+ While these three libraries offer similar features, they are not equal.
+ libcurl does not (yet) offer a standardized stable ABI if you decide to
+ switch from using libcurl-openssl to libcurl-gnutls or vice versa. The GnuTLS
+ and yassl support is very recent in libcurl and it has not been tested nor
+ used very extensively, while the OpenSSL equivalent code has been used and
+ thus matured since 1999.
+
+ GnuTLS
+ - LGPL licensened
+ - supports SRP
+ - lacks SSLv2 support
+ - lacks MD2 support (used by at least some CA certs)
+ - lacks the crypto functions libcurl uses for NTLM
+
+ OpenSSL
+ - Original BSD licensened
+ - lacks SRP
+ - supports SSLv2
+ - older and more widely used
+ - provides crypto functions libcurl uses for NTLM
+ - libcurl can do non-blocking connects with it in 7.15.4 and later
+
+ yassl
+ - GPL licensed
+ - much untested and unproven in the real work by (lib)curl users so we don't
+ know a lot about restrictions or benefits from using this
+
+The Better License, Original BSD, GPL or LGPL?
+
+ It isn't obvious or without debate to any objective interested party that
+ either of these licenses are the "better" or even the "preferred" one in a
+ generic situation.
+
+ Instead, I think we should accept the fact that the SSL/TLS libraries and
+ their different licenses will fit different applications and their authors
+ differently depending on the applications' licenses and their general usage
+ pattern (considering how GPL and LGPL libraries for example can be burdensome
+ for embedded systems usage).
+
+ In Debian land, there seems to be a common opinion that LGPL is "maximally
+ compatible" with apps while Original BSD is not. Like this:
+
+ http://lists.debian.org/debian-devel/2005/09/msg01417.html
+
+More SSL Libraries
+
+ In libcurl, there's no stopping us here. There are more Open Source/Free
+ SSL/TLS libraries out there and we would very much like to support them as
+ well, to offer application authors an even wider scope of choice.
+
+Application Angle of this Problem
+
+ libcurl is built to use one SSL/TLS library. It uses a single fixed name (by
+ default) on the built/created lib file, and applications are built/linked to
+ use that single lib. Replacing one libcurl instance with another one that
+ uses the other SSL/TLS library might break one or more applications (due to
+ ABI differences and/or different feature set). You want your application to
+ use the libcurl it was built for.
+
+Project cURL Angle of this Problem
+
+ We distribute libcurl and everyone may build libcurl with either library at
+ their choice. This problem is not directly a problem of ours. It merely
+ affects users - GPL application authors only - of our lib as it comes
+ included and delivered on some distros.
+
+ libcurl has different ABI when built with different SSL/TLS libraries due to
+ these reasons:
+
+ 1. No one has worked on fixing this. The mutex/lock callbacks should be set
+ with a generic libcurl function that should use the proper underlying
+ functions.
+
+ 2. The CURLOPT_SSL_CTX_FUNCTION option is not possible to "emulate" on GnuTLS
+ but simply requires OpenSSL.
+
+ 3. There might be some other subtle differences just because nobody has yet
+ tried to make a fixed ABI like this.
+
+Distro Angle of this Problem
+
+ To my knowledge there is only one distro that ships libcurl built with either
+ OpenSSL or GnuTLS.
+
+ Debian Linux is now (since mid September 2005) providing two different
+ libcurl packages, one for libcurl built with OpenSSL and one built with
+ GnuTLS. They use different .so names and can this both be installed in a
+ single system simultaneously. This has been said to be a transitional system
+ not desired to keep in the long run.
+
+Footnotes
+
+ [1] = http://www.xfree86.org/3.3.6/COPYRIGHT2.html#6
+ [2] = http://www.fsf.org/licensing/essays/bsd.html
+ [3] = http://www.fsf.org/licensing/licenses/gpl.html
+ [4] = http://curl.haxx.se/docs/copyright.html
+ [5] = http://www.openssl.org/source/license.html
+ [6] = http://www.fsf.org/licensing/licenses/gpl.html end of section 3
+ [7] = http://www.fsf.org/licensing/licenses/lgpl.html
+ [8] = http://en.wikipedia.org/wiki/OpenSSL_exception
+
+Feedback/Updates provided by
+
+ Eric Cooper
diff --git a/libs/libcurl/docs/FAQ b/libs/libcurl/docs/FAQ
new file mode 100644
index 0000000000..b6f8958afc
--- /dev/null
+++ b/libs/libcurl/docs/FAQ
@@ -0,0 +1,1476 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+FAQ
+
+ 1. Philosophy
+ 1.1 What is cURL?
+ 1.2 What is libcurl?
+ 1.3 What is curl not?
+ 1.4 When will you make curl do XXXX ?
+ 1.5 Who makes curl?
+ 1.6 What do you get for making curl?
+ 1.7 What about CURL from curl.com?
+ 1.8 I have a problem who do I mail?
+ 1.9 Where do I buy commercial support for curl?
+ 1.10 How many are using curl?
+ 1.11 Why don't you update ca-bundle.crt
+ 1.12 I have a problem who can I chat with?
+ 1.13 curl's ECCN number?
+ 1.14 How do I submit my patch?
+
+ 2. Install Related Problems
+ 2.1 configure doesn't find OpenSSL even when it is installed
+ 2.1.1 native linker doesn't find OpenSSL
+ 2.1.2 only the libssl lib is missing
+ 2.2 Does curl work/build with other SSL libraries?
+ 2.3 Where can I find a copy of LIBEAY32.DLL?
+ 2.4 Does curl support SOCKS (RFC 1928) ?
+
+ 3. Usage Problems
+ 3.1 curl: (1) SSL is disabled, https: not supported
+ 3.2 How do I tell curl to resume a transfer?
+ 3.3 Why doesn't my posting using -F work?
+ 3.4 How do I tell curl to run custom FTP commands?
+ 3.5 How can I disable the Accept: */* header?
+ 3.6 Does curl support ASP, XML, XHTML or HTML version Y?
+ 3.7 Can I use curl to delete/rename a file through FTP?
+ 3.8 How do I tell curl to follow HTTP redirects?
+ 3.9 How do I use curl in my favorite programming language?
+ 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP?
+ 3.11 How do I POST with a different Content-Type?
+ 3.12 Why do FTP specific features over HTTP proxy fail?
+ 3.13 Why does my single/double quotes fail?
+ 3.14 Does curl support Javascript or PAC (automated proxy config)?
+ 3.15 Can I do recursive fetches with curl?
+ 3.16 What certificates do I need when I use SSL?
+ 3.17 How do I list the root dir of an FTP server?
+ 3.18 Can I use curl to send a POST/PUT and not wait for a response?
+ 3.19 How do I get HTTP from a host using a specific IP address?
+ 3.20 How to SFTP from my user's home directory?
+ 3.21 Protocol xxx not supported or disabled in libcurl
+ 3.22 curl -X gives me HTTP problems
+
+ 4. Running Problems
+ 4.1 Problems connecting to SSL servers.
+ 4.2 Why do I get problems when I use & or % in the URL?
+ 4.3 How can I use {, }, [ or ] to specify multiple URLs?
+ 4.4 Why do I get downloaded data even though the web page doesn't exist?
+ 4.5 Why do I get return code XXX from a HTTP server?
+ 4.5.1 "400 Bad Request"
+ 4.5.2 "401 Unauthorized"
+ 4.5.3 "403 Forbidden"
+ 4.5.4 "404 Not Found"
+ 4.5.5 "405 Method Not Allowed"
+ 4.5.6 "301 Moved Permanently"
+ 4.6 Can you tell me what error code 142 means?
+ 4.7 How do I keep user names and passwords secret in Curl command lines?
+ 4.8 I found a bug!
+ 4.9 Curl can't authenticate to the server that requires NTLM?
+ 4.10 My HTTP request using HEAD, PUT or DELETE doesn't work!
+ 4.11 Why does my HTTP range requests return the full document?
+ 4.12 Why do I get "certificate verify failed" ?
+ 4.13 Why is curl -R on Windows one hour off?
+ 4.14 Redirects work in browser but not with curl!
+ 4.15 FTPS doesn't work
+ 4.16 My HTTP POST or PUT requests are slow!
+ 4.17 Non-functional connect timeouts on Windows
+ 4.18 file:// URLs containing drive letters (Windows, NetWare)
+ 4.19 Why doesn't cURL return an error when the network cable is unplugged?
+
+ 5. libcurl Issues
+ 5.1 Is libcurl thread-safe?
+ 5.2 How can I receive all data into a large memory chunk?
+ 5.3 How do I fetch multiple files with libcurl?
+ 5.4 Does libcurl do Winsock initing on win32 systems?
+ 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ?
+ 5.6 What about Keep-Alive or persistent connections?
+ 5.7 Link errors when building libcurl on Windows!
+ 5.8 libcurl.so.X: open failed: No such file or directory
+ 5.9 How does libcurl resolve host names?
+ 5.10 How do I prevent libcurl from writing the response to stdout?
+ 5.11 How do I make libcurl not receive the whole HTTP response?
+ 5.12 Can I make libcurl fake or hide my real IP address?
+ 5.13 How do I stop an ongoing transfer?
+ 5.14 Using C++ non-static functions for callbacks?
+ 5.15 How do I get an FTP directory listing?
+ 5.16 I want a different time-out!
+ 5.17 Can I write a server with libcurl?
+
+ 6. License Issues
+ 6.1 I have a GPL program, can I use the libcurl library?
+ 6.2 I have a closed-source program, can I use the libcurl library?
+ 6.3 I have a BSD licensed program, can I use the libcurl library?
+ 6.4 I have a program that uses LGPL libraries, can I use libcurl?
+ 6.5 Can I modify curl/libcurl for my program and keep the changes secret?
+ 6.6 Can you please change the curl/libcurl license to XXXX?
+ 6.7 What are my obligations when using libcurl in my commercial apps?
+
+ 7. PHP/CURL Issues
+ 7.1 What is PHP/CURL?
+ 7.2 Who wrote PHP/CURL?
+ 7.3 Can I perform multiple requests using the same handle?
+
+==============================================================================
+
+1. Philosophy
+
+ 1.1 What is cURL?
+
+ cURL is the name of the project. The name is a play on 'Client for URLs',
+ originally with URL spelled in uppercase to make it obvious it deals with
+ URLs. The fact it can also be pronounced 'see URL' also helped, it works as
+ an abbreviation for "Client URL Request Library" or why not the recursive
+ version: "Curl URL Request Library".
+
+ The cURL project produces two products:
+
+ libcurl
+
+ A free and easy-to-use client-side URL transfer library, supporting DICT,
+ FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3,
+ POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP.
+
+ libcurl supports HTTPS certificates, HTTP POST, HTTP PUT, FTP uploading,
+ kerberos, HTTP form based upload, proxies, cookies, user+password
+ authentication, file transfer resume, http proxy tunneling and more!
+
+ libcurl is highly portable, it builds and works identically on numerous
+ platforms, including Solaris, NetBSD, FreeBSD, OpenBSD, Darwin, HPUX,
+ IRIX, AIX, Tru64, Linux, UnixWare, HURD, Windows, Amiga, OS/2, BeOS, Mac
+ OS X, Ultrix, QNX, OpenVMS, RISC OS, Novell NetWare, DOS, Symbian, OSF,
+ Android, Minix, IBM TPF and more...
+
+ libcurl is free, thread-safe, IPv6 compatible, feature rich, well
+ supported and fast.
+
+ curl
+
+ A command line tool for getting or sending files using URL syntax.
+
+ Since curl uses libcurl, curl supports the same wide range of common
+ Internet protocols that libcurl does.
+
+ We pronounce curl and cURL with an initial k sound: [kurl].
+
+ There are numerous sub-projects and related projects that also use the word
+ curl in the project names in various combinations, but you should take
+ notice that this FAQ is directed at the command-line tool named curl (and
+ libcurl the library), and may therefore not be valid for other curl-related
+ projects. (There is however a small section for the PHP/CURL in this FAQ.)
+
+ 1.2 What is libcurl?
+
+ libcurl is a reliable and portable library which provides you with an easy
+ interface to a range of common Internet protocols.
+
+ You can use libcurl for free in your application, be it open source,
+ commercial or closed-source.
+
+ libcurl is most probably the most portable, most powerful and most often
+ used C-based multi-platform file transfer library on this planet - be it
+ open source or commercial.
+
+ 1.3 What is curl not?
+
+ Curl is not a wget clone. That is a common misconception. Never, during
+ curl's development, have we intended curl to replace wget or compete on its
+ market. Curl is targeted at single-shot file transfers.
+
+ Curl is not a web site mirroring program. If you want to use curl to mirror
+ something: fine, go ahead and write a script that wraps around curl to make
+ it reality (like curlmirror.pl does).
+
+ Curl is not an FTP site mirroring program. Sure, get and send FTP with curl
+ but if you want systematic and sequential behavior you should write a
+ script (or write a new program that interfaces libcurl) and do it.
+
+ Curl is not a PHP tool, even though it works perfectly well when used from
+ or with PHP (when using the PHP/CURL module).
+
+ Curl is not a program for a single operating system. Curl exists, compiles,
+ builds and runs under a wide range of operating systems, including all
+ modern Unixes (and a bunch of older ones too), Windows, Amiga, BeOS, OS/2,
+ OS X, QNX etc.
+
+ 1.4 When will you make curl do XXXX ?
+
+ We love suggestions of what to change in order to make curl and libcurl
+ 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.
+
+ 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.
+
+ 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.
+
+ 1.5 Who makes curl?
+
+ curl and libcurl are not made by any single individual. Daniel Stenberg is
+ project leader and main developer, but other persons' submissions are
+ important and crucial. Anyone can contribute and post their changes and
+ improvements and have them inserted in the main sources (of course on the
+ condition that developers agree on that the fixes are good).
+
+ The full list of all contributors is found in the docs/THANKS file.
+
+ curl is developed by a community, with Daniel at the wheel.
+
+ 1.6 What do you get for making curl?
+
+ Project cURL is entirely free and open. No person gets paid for developing
+ (lib)curl on full or even part time. We do this voluntarily on our spare
+ time. Occasionally companies pay individual developers to work on curl, but
+ that's up to each company and developer. It is not controlled by nor
+ supervised in any way by the project.
+
+ We still get help from companies. Haxx provides web site, bandwidth, mailing
+ lists etc, sourceforge.net hosts project services we take advantage from,
+ like the bug tracker and github hosts the primary git repository. Also
+ again, some companies have sponsored certain parts of the development in the
+ past and I hope some will continue to do so in the future.
+
+ If you want to support our project, consider a donation or a banner-program
+ or even better: by helping us coding, documenting, testing etc.
+
+ 1.7 What about CURL from curl.com?
+
+ During the summer 2001, curl.com was busy advertising their client-side
+ programming language for the web, named CURL.
+
+ We are in no way associated with curl.com or their CURL programming
+ language.
+
+ 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
+ rights to the name.
+
+ We recognize that we will be living in parallel with curl.com and wish them
+ every success.
+
+ 1.8 I have a problem who do I mail?
+
+ Please do not mail any single individual unless you really need to. Keep
+ curl-related questions on a suitable mailing list. All available mailing
+ lists are listed in the MANUAL document and online at
+ http://curl.haxx.se/mail/
+
+ Keeping curl-related questions and discussions on mailing lists allows
+ others to join in and help, to share their ideas, contribute their
+ suggestions and spread their wisdom. Keeping discussions on public mailing
+ lists also allows for others to learn from this (both current and future
+ users thanks to the web based archives of the mailing lists), thus saving us
+ from having to repeat ourselves even more. Thanks for respecting this.
+
+ If you have found or simply suspect a security problem in curl or libcurl,
+ mail curl-security at haxx.se (closed list of receivers, mails are not
+ disclosed) and tell. Then we can produce a fix in a timely manner before the
+ flaw is announced to the world, thus lessen the impact the problem will have
+ on existing users.
+
+ 1.9 Where do I buy commercial support for curl?
+
+ curl is fully open source. It means you can hire any skilled engineer to fix
+ your curl-related problems.
+
+ We list available alternatives on the curl web site:
+ http://curl.haxx.se/support.html
+
+ 1.10 How many are using curl?
+
+ It is impossible to tell.
+
+ We don't know how many users that knowingly have installed and use curl.
+
+ We don't know how many users that use curl without knowing that they are in
+ fact using it.
+
+ We don't know how many users that downloaded or installed curl and then
+ never use it.
+
+ In May 2012 Daniel did a counting game and came up with a number that may
+ be completely wrong or somewhat accurate. Over 500 million!
+
+ See http://daniel.haxx.se/blog/2012/05/16/300m-users/
+
+ 1.11 Why don't you update ca-bundle.crt
+
+ The ca cert bundle that used to shipped with curl was very outdated and must
+ be replaced with an up-to-date version by anyone who wants to verify
+ peers. It is no longer provided by curl. The last curl release ever that
+ shipped a ca cert bundle was curl 7.18.0.
+
+ In the cURL project we've decided not to attempt to keep this file updated
+ (or even present anymore) since deciding what to add to a ca cert bundle is
+ an undertaking we've not been ready to accept, and the one we can get from
+ Mozilla is perfectly fine so there's no need to duplicate that work.
+
+ Today, with many services performed over HTTPS, every operating system
+ should come with a default ca cert bundle that can be deemed somewhat
+ trustworthy and that collection (if reasonably updated) should be deemed to
+ be a lot better than a private curl version.
+
+ If you want the most recent collection of ca certs that Mozilla Firefox
+ uses, we recommend that you extract the collection yourself from Mozilla
+ Firefox (by running 'make ca-bundle), or by using our online service setup
+ for this purpose: http://curl.haxx.se/docs/caextract.html
+
+ 1.12 I have a problem who can I chat with?
+
+ There's a bunch of friendly people hanging out in the #curl channel on the
+ IRC network irc.freenode.net. If you're polite and nice, chances are big
+ that you can get -- or provide -- help instantly.
+
+ 1.13 curl's ECCN number?
+
+ The US government restricts exports of software that contains or uses
+ cryptography. When doing so, the Export Control Classification Number (ECCN)
+ is used to identify the level of export control etc.
+
+ ASF gives a good explanation at http://www.apache.org/dev/crypto.html
+
+ We believe curl's number might be ECCN 5D002, another possibility is
+ 5D992. It seems necessary to write them, asking to confirm.
+
+ Comprehensible explanations of the meaning of such numbers and how to
+ obtain them (resp.) are here
+
+ http://www.bis.doc.gov/licensing/exportingbasics.htm
+ http://www.bis.doc.gov/licensing/do_i_needaneccn.html
+
+ An incomprehensible description of the two numbers above is here
+ http://www.access.gpo.gov/bis/ear/pdf/ccl5-pt2.pdf
+
+ 1.14 How do I submit my patch?
+
+ When you have made a patch or a change of whatever sort, and want to submit
+ that to the project, there are a few different ways we prefer:
+
+ o send a patch to the curl-library mailing list. We're many subscribers
+ there and there are lots of people who can review patches, comment on them
+ and "receive" them properly.
+
+ o if your patch changes or fixes a bug, you can also opt to submit a bug
+ report in the bug tracker and attach your patch there. There are less
+ people involved there.
+
+ Lots of more details are found in the CONTRIBUTE and INTERNALS docs.
+
+
+2. Install Related Problems
+
+ 2.1 configure doesn't find OpenSSL even when it is installed
+
+ This may be because of several reasons.
+
+ 2.1.1 native linker doesn't find openssl
+
+ Affected platforms:
+ Solaris (native cc compiler)
+ HPUX (native cc compiler)
+ SGI IRIX (native cc compiler)
+ SCO UNIX (native cc compiler)
+
+ When configuring curl, I specify --with-ssl. OpenSSL is installed in
+ /usr/local/ssl Configure reports SSL in /usr/local/ssl, but fails to find
+ CRYPTO_lock in -lcrypto
+
+ Cause: The cc for this test places the -L/usr/local/ssl/lib AFTER
+ -lcrypto, so ld can't find the library. This is due to a bug in the GNU
+ autoconf tool.
+
+ Workaround: Specifying "LDFLAGS=-L/usr/local/ssl/lib" in front of
+ ./configure places the -L/usr/local/ssl/lib early enough in the command
+ line to make things work
+
+ 2.1.2 only the libssl lib is missing
+
+ If all include files and the libcrypto lib is present, with only the
+ libssl being missing according to configure, this is mostly likely because
+ a few functions are left out from the libssl.
+
+ If the function names missing include RSA or RSAREF you can be certain
+ that this is because libssl requires the RSA and RSAREF libs to build.
+
+ See the INSTALL file section that explains how to add those libs to
+ configure. Make sure that you remove the config.cache file before you
+ rerun configure with the new flags.
+
+ 2.2 Does curl work/build with other SSL libraries?
+
+ Curl has been written to use a generic SSL function layer internally, and
+ that SSL functionality can then be provided by one out of many different SSL
+ backends.
+
+ curl can be built to use one of the following SSL alternatives: OpenSSL,
+ GnuTLS, yassl, NSS, PolarSSL, axTLS, Secure Transport (native iOS/OS X),
+ schannel (native Windows) or qssl (native IBM i). They all have their pros
+ and cons, and we try to maintain a comparison of them here:
+ http://curl.haxx.se/docs/ssl-compared.html
+
+ 2.3 Where can I find a copy of LIBEAY32.DLL?
+
+ That is an OpenSSL binary built for Windows.
+
+ Curl can be built with OpenSSL to do the SSL stuff. The LIBEAY32.DLL is then
+ what curl needs on a windows machine to do https:// etc. Check out the curl
+ web site to find accurate and up-to-date pointers to recent OpenSSL DLLs and
+ other binary packages.
+
+ 2.4 Does curl support SOCKS (RFC 1928) ?
+
+ Yes, SOCKS 4 and 5 are supported.
+
+
+3. Usage problems
+
+ 3.1 curl: (1) SSL is disabled, https: not supported
+
+ If you get this output when trying to get anything from a https:// server,
+ it means that the instance of curl/libcurl that you're using was built
+ without support for this protocol.
+
+ This could've happened if the configure script that was run at build time
+ couldn't find all libs and include files curl requires for SSL to work. If
+ the configure script fails to find them, curl is simply built without SSL
+ support.
+
+ To get the https:// support into a curl that was previously built but that
+ reports that https:// is not supported, you should dig through the document
+ and logs and check out why the configure script doesn't find the SSL libs
+ and/or include files.
+
+ Also, check out the other paragraph in this FAQ labelled "configure doesn't
+ find OpenSSL even when it is installed".
+
+ 3.2 How do I tell curl to resume a transfer?
+
+ Curl supports resumed transfers both ways on both FTP and HTTP.
+ Try the -C option.
+
+ 3.3 Why doesn't my posting using -F work?
+
+ You can't simply use -F or -d at your choice. The web server that will
+ receive your post expects one of the formats. If the form you're trying to
+ submit uses the type 'multipart/form-data', then and only then you must use
+ the -F type. In all the most common cases, you should use -d which then
+ causes a posting with the type 'application/x-www-form-urlencoded'.
+
+ This is described in some detail in the MANUAL and TheArtOfHttpScripting
+ documents, and if you don't understand it the first time, read it again
+ before you post questions about this to the mailing list. Also, try reading
+ through the mailing list archives for old postings and questions regarding
+ this.
+
+ 3.4 How do I tell curl to run custom FTP commands?
+
+ You can tell curl to perform optional commands both before and/or after a
+ file transfer. Study the -Q/--quote option.
+
+ Since curl is used for file transfers, you don't normally use curl to
+ perform FTP commands without transferring anything. Therefore you must
+ always specify a URL to transfer to/from even when doing custom FTP
+ commands, or use -I which implies the "no body" option sent to libcurl.
+
+ 3.5 How can I disable the Accept: */* header?
+
+ You can change all internally generated headers by adding a replacement with
+ the -H/--header option. By adding a header with empty contents you safely
+ disable that one. Use -H "Accept:" to disable that specific header.
+
+ 3.6 Does curl support ASP, XML, XHTML or HTML version Y?
+
+ To curl, all contents are alike. It doesn't matter how the page was
+ generated. It may be ASP, PHP, Perl, shell-script, SSI or plain HTML
+ files. There's no difference to curl and it doesn't even know what kind of
+ language that generated the page.
+
+ See also item 3.14 regarding javascript.
+
+ 3.7 Can I use curl to delete/rename a file through FTP?
+
+ Yes. You specify custom FTP commands with -Q/--quote.
+
+ One example would be to delete a file after you have downloaded it:
+
+ curl -O ftp://download.com/coolfile -Q '-DELE coolfile'
+
+ or rename a file after upload:
+
+ curl -T infile ftp://upload.com/dir/ -Q "-RNFR infile" -Q "-RNTO newname"
+
+ 3.8 How do I tell curl to follow HTTP redirects?
+
+ Curl does not follow so-called redirects by default. The Location: header
+ that informs the client about this is only interpreted if you're using the
+ -L/--location option. As in:
+
+ curl -L http://redirector.com
+
+ Not all redirects are HTTP ones, see 4.14
+
+ 3.9 How do I use curl in my favorite programming language?
+
+ There exist many language interfaces/bindings for curl that integrates it
+ better with various languages. If you are fluid in a script language, you
+ may very well opt to use such an interface instead of using the command line
+ tool.
+
+ Find out more about which languages that support curl directly, and how to
+ install and use them, in the libcurl section of the curl web site:
+ http://curl.haxx.se/libcurl/
+
+ All the various bindings to libcurl are made by other projects and people,
+ outside of the cURL project. The cURL project itself only produces libcurl
+ with its plain C API. If you don't find anywhere else to ask you can ask
+ about bindings on the curl-library list too, but be prepared that people on
+ that list may not know anything about bindings.
+
+ In October 2009, there were interfaces available for the following
+ languages: Ada95, Basic, C, C++, Ch, Cocoa, D, Dylan, Eiffel, Euphoria,
+ Ferite, Gambas, glib/GTK+, Haskell, ILE/RPG, Java, Lisp, Lua, Mono, .NET,
+ Object-Pascal, O'Caml, Pascal, Perl, PHP, PostgreSQL, Python, R, Rexx, Ruby,
+ Scheme, S-Lang, Smalltalk, SP-Forth, SPL, Tcl, Visual Basic, Visual FoxPro,
+ Q, wxwidgets and XBLite. By the time you read this, additional ones may have
+ appeared!
+
+ 3.10 What about SOAP, WebDAV, XML-RPC or similar protocols over HTTP?
+
+ Curl adheres to the HTTP spec, which basically means you can play with *any*
+ protocol that is built on top of HTTP. Protocols such as SOAP, WEBDAV and
+ XML-RPC are all such ones. You can use -X to set custom requests and -H to
+ set custom headers (or replace internally generated ones).
+
+ Using libcurl is of course just as fine and you'd just use the proper
+ library options to do the same.
+
+ 3.11 How do I POST with a different Content-Type?
+
+ You can always replace the internally generated headers with -H/--header.
+ To make a simple HTTP POST with text/xml as content-type, do something like:
+
+ curl -d "datatopost" -H "Content-Type: text/xml" [URL]
+
+ 3.12 Why do FTP specific features over HTTP proxy fail?
+
+ Because when you use a HTTP proxy, the protocol spoken on the network will
+ be HTTP, even if you specify a FTP URL. This effectively means that you
+ normally can't use FTP specific features such as FTP upload and FTP quote
+ etc.
+
+ There is one exception to this rule, and that is if you can "tunnel through"
+ the given HTTP proxy. Proxy tunneling is enabled with a special option (-p)
+ and is generally not available as proxy admins usually disable tunneling to
+ other ports than 443 (which is used for HTTPS access through proxies).
+
+ 3.13 Why does my single/double quotes fail?
+
+ To specify a command line option that includes spaces, you might need to
+ put the entire option within quotes. Like in:
+
+ curl -d " with spaces " url.com
+
+ or perhaps
+
+ curl -d ' with spaces ' url.com
+
+ Exactly what kind of quotes and how to do this is entirely up to the shell
+ or command line interpreter that you are using. For most unix shells, you
+ can more or less pick either single (') or double (") quotes. For
+ Windows/DOS prompts I believe you're forced to use double (") quotes.
+
+ Please study the documentation for your particular environment. Examples in
+ the curl docs will use a mix of both these ones as shown above. You must
+ adjust them to work in your environment.
+
+ Remember that curl works and runs on more operating systems than most single
+ individuals have ever tried.
+
+ 3.14 Does curl support Javascript or PAC (automated proxy config)?
+
+ Many web pages do magic stuff using embedded Javascript. Curl and libcurl
+ have no built-in support for that, so it will be treated just like any other
+ contents.
+
+ .pac files are a netscape invention and are sometimes used by organizations
+ to allow them to differentiate which proxies to use. The .pac contents is
+ just a Javascript program that gets invoked by the browser and that returns
+ the name of the proxy to connect to. Since curl doesn't support Javascript,
+ it can't support .pac proxy configuration either.
+
+ 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.
+
+ Read the Javascript code and rewrite the same logic in another language.
+
+ 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.
+
+ 3.15 Can I do recursive fetches with curl?
+
+ No. curl itself has no code that performs recursive operations, such as
+ those performed by wget and similar tools.
+
+ There exist wrapper scripts with that functionality (for example the
+ curlmirror perl script), and you can write programs based on libcurl to do
+ it, but the command line tool curl itself cannot.
+
+ 3.16 What certificates do I need when I use SSL?
+
+ 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.
+
+ 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.
+
+ 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
+ certificate. Server certificate verification is enabled by default in curl
+ and libcurl and is often the reason for problems as explained in FAQ entry
+ 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.
+
+ 3.17 How do I list the root dir of an FTP server?
+
+ There are two ways. The way defined in the RFC is to use an encoded slash
+ in the first path part. List the "/tmp" dir like this:
+
+ curl ftp://ftp.sunet.se/%2ftmp/
+
+ or the not-quite-kosher-but-more-readable way, by simply starting the path
+ section of the URL with a slash:
+
+ curl ftp://ftp.sunet.se//tmp/
+
+ 3.18 Can I use curl to send a POST/PUT and not wait for a response?
+
+ No.
+
+ But you could easily write your own program using libcurl to do such stunts.
+
+ 3.19 How do I get HTTP from a host using a specific IP address?
+
+ For example, you may be trying out a web site installation that isn't yet in
+ the DNS. Or you have a site using multiple IP addresses for a given host
+ name and you want to address a specific one out of the set.
+
+ Set a custom Host: header that identifies the server name you want to reach
+ but use the target IP address in the URL:
+
+ curl --header "Host: www.example.com" http://127.0.0.1/
+
+ You can also opt to add faked host name entries to curl with the --resolve
+ option. That has the added benefit that things like redirects will also work
+ properly. The above operation would instead be done as:
+
+ curl --resolve www.example.com:80:127.0.0.1 http://www.example.com/
+
+ 3.20 How to SFTP from my user's home directory?
+
+ Contrary to how FTP works, SFTP and SCP URLs specify the exact directory to
+ work with. It means that if you don't specify that you want the user's home
+ directory, you get the actual root directory.
+
+ To specify a file in your user's home directory, you need to use the correct
+ URL syntax which for sftp might look similar to:
+
+ curl -O -u user:password sftp://example.com/~/file.txt
+
+ and for SCP it is just a different protocol prefix:
+
+ curl -O -u user:password scp://example.com/~/file.txt
+
+ 3.21 Protocol xxx not supported or disabled in libcurl
+
+ 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 (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.
+
+ Note that this error will also occur if you pass a wrongly spelled protocol
+ part as in "htpt://example.com" or as in the less evident case if you prefix
+ the protocol part with a space as in " http://example.com/".
+
+ 3.22 curl -X gives me HTTP problems
+
+ In normal circumstances, -X should hardly ever be used.
+
+ By default you use curl without explicitly saying which request method to
+ use when the URL identifies a HTTP transfer. If you just pass in a URL like
+ "curl http://example.com" it will use GET. If you use -d or -F curl will use
+ POST, -I will cause a HEAD and -T will make it a PUT.
+
+ If for whatever reason you're not happy with these default choices that curl
+ does for you, you can override those request methods by specifying -X
+ [WHATEVER]. This way you can for example send a DELETE by doing "curl -X
+ DELETE [URL]".
+
+ It is thus pointless to do "curl -XGET [URL]" as GET would be used
+ anyway. In the same vein it is pointless to do "curl -X POST -d data
+ [URL]"... But you can make a fun and somewhat rare request that sends a
+ request-body in a GET request with something like "curl -X GET -d data
+ [URL]"
+
+ Note that -X doesn't change curl's behavior. It only modifies the actual
+ string sent in the request.
+
+ Accordingly, by using -XPOST on a command line that for example would follow
+ a 303 redirect, you will effectively prevent curl from behaving
+ correctly. Be aware.
+
+
+4. Running Problems
+
+ 4.1 Problems connecting to SSL servers.
+
+ It took a very long time before we could sort out why curl had problems to
+ connect to certain SSL servers when using SSLeay or OpenSSL v0.9+. The
+ error sometimes showed up similar to:
+
+ 16570:error:1407D071:SSL routines:SSL2_READ:bad mac decode:s2_pkt.c:233:
+
+ It turned out to be because many older SSL servers don't deal with SSLv3
+ requests properly. To correct this problem, tell curl to select SSLv2 from
+ the command line (-2/--sslv2).
+
+ There have also been examples where the remote server didn't like the SSLv2
+ request and instead you had to force curl to use SSLv3 with -3/--sslv3.
+
+ 4.2 Why do I get problems when I use & or % in the URL?
+
+ In general unix shells, the & symbol is treated specially and when used, it
+ runs the specified command in the background. To safely send the & as a part
+ of a URL, you should quote the entire URL by using single (') or double (")
+ quotes around it. Similar problems can also occur on some shells with other
+ characters, including ?*!$~(){}<>\|;`. When in doubt, quote the URL.
+
+ An example that would invoke a remote CGI that uses &-symbols could be:
+
+ curl 'http://www.altavista.com/cgi-bin/query?text=yes&q=curl'
+
+ 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.
+
+ 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?
+
+ Because those letters have a special meaning to the shell, and to be used in
+ a URL specified to curl you must quote them.
+
+ An example that downloads two URLs (sequentially) would do:
+
+ curl '{curl,www}.haxx.se'
+
+ To be able to use those letters as actual parts of the URL (without using
+ them for the curl URL "globbing" system), use the -g/--globoff option:
+
+ curl -g 'www.site.com/weirdname[].html'
+
+ 4.4 Why do I get downloaded data even though the web page doesn't exist?
+
+ Curl asks remote servers for the page you specify. If the page doesn't exist
+ at the server, the HTTP protocol defines how the server should respond and
+ that means that headers and a "page" will be returned. That's simply how
+ HTTP works.
+
+ By using the --fail option you can tell curl explicitly to not get any data
+ if the HTTP return code doesn't say success.
+
+ 4.5 Why do I get return code XXX from a HTTP server?
+
+ RFC2616 clearly explains the return codes. This is a short transcript. Go
+ read the RFC for exact details:
+
+ 4.5.1 "400 Bad Request"
+
+ The request could not be understood by the server due to malformed
+ syntax. The client SHOULD NOT repeat the request without modifications.
+
+ 4.5.2 "401 Unauthorized"
+
+ The request requires user authentication.
+
+ 4.5.3 "403 Forbidden"
+
+ The server understood the request, but is refusing to fulfil it.
+ Authorization will not help and the request SHOULD NOT be repeated.
+
+ 4.5.4 "404 Not Found"
+
+ The server has not found anything matching the Request-URI. No indication
+ is given of whether the condition is temporary or permanent.
+
+ 4.5.5 "405 Method Not Allowed"
+
+ The method specified in the Request-Line is not allowed for the resource
+ identified by the Request-URI. The response MUST include an Allow header
+ containing a list of valid methods for the requested resource.
+
+ 4.5.6 "301 Moved Permanently"
+
+ If you get this return code and an HTML output similar to this:
+
+ <H1>Moved Permanently</H1> The document has moved <A
+ HREF="http://same_url_now_with_a_trailing_slash/">here</A>.
+
+ it might be because you request a directory URL but without the trailing
+ slash. Try the same operation again _with_ the trailing URL, or use the
+ -L/--location option to follow the redirection.
+
+ 4.6 Can you tell me what error code 142 means?
+
+ All curl error codes are described at the end of the man page, in the
+ section called "EXIT CODES".
+
+ Error codes that are larger than the highest documented error code means
+ that curl has exited due to a crash. This is a serious error, and we
+ appreciate a detailed bug report from you that describes how we could go
+ ahead and repeat this!
+
+ 4.7 How do I keep user names and passwords secret in Curl command lines?
+
+ This problem has two sides:
+
+ The first part is to avoid having clear-text passwords in the command line
+ so that they don't appear in 'ps' outputs and similar. That is easily
+ avoided by using the "-K" option to tell curl to read parameters from a file
+ or stdin to which you can pass the secret info. curl itself will also
+ attempt to "hide" the given password by blanking out the option - this
+ doesn't work on all platforms.
+
+ To keep the passwords in your account secret from the rest of the world is
+ not a task that curl addresses. You could of course encrypt them somehow to
+ at least hide them from being read by human eyes, but that is not what
+ anyone would call security.
+
+ Also note that regular HTTP (using Basic authentication) and FTP passwords
+ are sent in clear across the network. All it takes for anyone to fetch them
+ is to listen on the network. Eavesdropping is very easy. Use more secure
+ authentication methods (like Digest, Negotiate or even NTLM) or consider the
+ SSL-based alternatives HTTPS and FTPS.
+
+ 4.8 I found a bug!
+
+ It is not a bug if the behavior is documented. Read the docs first.
+ Especially check out the KNOWN_BUGS file, it may be a documented bug!
+
+ If it is a problem with a binary you've downloaded or a package for your
+ particular platform, try contacting the person who built the package/archive
+ you have.
+
+ If there is a bug, read the BUGS document first. Then report it as described
+ in there.
+
+ 4.9 Curl can't authenticate to the server that requires NTLM?
+
+ NTLM support requires OpenSSL, GnuTLS, NSS, Secure Transport, or Microsoft
+ Windows libraries at build-time to provide this functionality.
+
+ NTLM is a Microsoft proprietary protocol. Proprietary formats are evil. You
+ should not use such ones.
+
+ 4.10 My HTTP request using HEAD, PUT or DELETE doesn't work!
+
+ Many web servers allow or demand that the administrator configures the
+ server properly for these requests to work on the web server.
+
+ Some servers seem to support HEAD only on certain kinds of URLs.
+
+ To fully grasp this, try the documentation for the particular server
+ software you're trying to interact with. This is not anything curl can do
+ anything about.
+
+ 4.11 Why does my HTTP range requests return the full document?
+
+ Because the range may not be supported by the server, or the server may
+ choose to ignore it and return the full document anyway.
+
+ 4.12 Why do I get "certificate verify failed" ?
+
+ You invoke curl 7.10 or later to communicate on a https:// URL and get an
+ error back looking something similar to this:
+
+ curl: (35) SSL: error:14090086:SSL routines:
+ SSL3_GET_SERVER_CERTIFICATE:certificate verify failed
+
+ Then it means that curl couldn't verify that the server's certificate was
+ good. Curl verifies the certificate using the CA cert bundle that comes with
+ the curl installation.
+
+ To disable the verification (which makes it act like curl did before 7.10),
+ use -k. This does however enable man-in-the-middle attacks.
+
+ If you get this failure but are having a CA cert bundle installed and used,
+ the server's certificate is not signed by one of the CA's in the bundle. It
+ might for example be self-signed. You then correct this problem by obtaining
+ a valid CA cert for the server. Or again, decrease the security by disabling
+ this check.
+
+ Details are also in the SSLCERTS file in the release archives, found online
+ here: http://curl.haxx.se/docs/sslcerts.html
+
+ 4.13 Why is curl -R on Windows one hour off?
+
+ During daylight savings time, when -R is used, curl will set a time that
+ appears one hour off. This happens due to a flaw in how Windows stores and
+ uses file modification times and it is not easily worked around. For details
+ on this problem, read this: http://www.codeproject.com/datetime/dstbugs.asp
+
+ 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 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.
+
+ 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
+ parses the results and fetches the new URL.
+
+ 4.15 FTPS doesn't work
+
+ curl supports FTPS (sometimes known as FTP-SSL) both implicit and explicit
+ mode.
+
+ When a URL is used that starts with FTPS://, curl assumes implicit SSL on
+ the control connection and will therefore immediately connect and try to
+ speak SSL. FTPS:// connections default to port 990.
+
+ To use explicit FTPS, you use a FTP:// URL and the --ftp-ssl option (or one
+ of its related flavours). This is the most common method, and the one
+ mandated by RFC4217. This kind of connection then of course uses the
+ standard FTP port 21 by default.
+
+ 4.16 My HTTP POST or PUT requests are slow!
+
+ libcurl makes all POST and PUT requests (except for POST requests with a
+ very tiny request body) use the "Expect: 100-continue" header. This header
+ allows the server to deny the operation early so that libcurl can bail out
+ already before having to send any data. This is useful in authentication
+ cases and others.
+
+ However, many servers don't implement the Expect: stuff properly and if the
+ server doesn't respond (positively) within 1 second libcurl will continue
+ and send off the data anyway.
+
+ You can disable libcurl's use of the Expect: header the same way you disable
+ any header, using -H / CURLOPT_HTTPHEADER, or by forcing it to use HTTP 1.0.
+
+ 4.17 Non-functional connect timeouts
+
+ In most Windows setups having a timeout longer than 21 seconds make no
+ difference, as it will only send 3 TCP SYN packets and no more. The second
+ packet sent three seconds after the first and the third six seconds after
+ the second. No more than three packets are sent, no matter how long the
+ timeout is set.
+
+ See option TcpMaxConnectRetransmissions on this page:
+ http://support.microsoft.com/?scid=kb%3Ben-us%3B175523&x=6&y=7
+
+ Also, even on non-Windows systems there may run a firewall or anti-virus
+ software or similar that accepts the connection but does not actually do
+ anything else. This will make (lib)curl to consider the connection connected
+ and thus the connect timeout won't trigger.
+
+ 4.18 file:// URLs containing drive letters (Windows, NetWare)
+
+ When using cURL to try to download a local file, one might use a URL
+ in this format:
+
+ file://D:/blah.txt
+
+ You'll find that even if D:\blah.txt does exist, cURL returns a 'file
+ not found' error.
+
+ According to RFC 1738 (http://www.faqs.org/rfcs/rfc1738.html),
+ file:// URLs must contain a host component, but it is ignored by
+ most implementations. In the above example, 'D:' is treated as the
+ host component, and is taken away. Thus, cURL tries to open '/blah.txt'.
+ If your system is installed to drive C:, that will resolve to 'C:\blah.txt',
+ and if that doesn't exist you will get the not found error.
+
+ To fix this problem, use file:// URLs with *three* leading slashes:
+
+ file:///D:/blah.txt
+
+ Alternatively, if it makes more sense, specify 'localhost' as the host
+ component:
+
+ file://localhost/D:/blah.txt
+
+ In either case, cURL should now be looking for the correct file.
+
+ 4.19 Why doesn't cURL return an error when the network cable is unplugged?
+
+ 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 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
+ perfectly legal for the client wait indefinitely for data, the stack may
+ never report a problem, and even when it does, it can take up to 20 minutes
+ for it to detect an issue. The curl option --keepalive-time enables
+ keep-alive support in the TCP/IP stack which makes it periodically probe the
+ connection to make sure it is still available to send data. That should
+ reliably detect any TCP/IP network failure.
+
+ But even that won't detect the network going down before the TCP/IP
+ connection is established (e.g. during a DNS lookup) or using protocols that
+ don't use TCP. To handle those situations, curl offers a number of timeouts
+ on its own. --speed-limit/--speed-time will abort if the data transfer rate
+ 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
+
+ 5.1 Is libcurl thread-safe?
+
+ Yes.
+
+ 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. 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:
+
+ http://www.openssl.org/docs/crypto/threads.html
+
+ If you use a GnuTLS-powered libcurl in a multi-threaded environment, you
+ need to provide locking function(s) for libgcrypt (which is used by GnuTLS
+ for the crypto functions).
+
+ http://www.gnu.org/software/gnutls/manual/html_node/Multi_002dthreaded-applications.html
+
+ No special locking is needed with a NSS-powered libcurl. NSS is thread-safe.
+
+ 5.2 How can I receive all data into a large memory chunk?
+
+ [ See also the examples/getinmemory.c source ]
+
+ You are in full control of the callback function that gets called every time
+ there is data received from the remote server. You can make that callback do
+ whatever you want. You do not have to write the received data to a file.
+
+ One solution to this problem could be to have a pointer to a struct that you
+ pass to the callback function. You set the pointer using the
+ CURLOPT_WRITEDATA option. Then that pointer will be passed to the callback
+ instead of a FILE * to a file:
+
+ /* imaginary struct */
+ struct MemoryStruct {
+ char *memory;
+ size_t size;
+ };
+
+ /* imaginary callback function */
+ size_t
+ WriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
+ {
+ size_t realsize = size * nmemb;
+ struct MemoryStruct *mem = (struct MemoryStruct *)data;
+
+ mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
+ if (mem->memory) {
+ memcpy(&(mem->memory[mem->size]), ptr, realsize);
+ mem->size += realsize;
+ mem->memory[mem->size] = 0;
+ }
+ return realsize;
+ }
+
+ 5.3 How do I fetch multiple files with libcurl?
+
+ libcurl has excellent support for transferring multiple files. You should
+ just repeatedly set new URLs with curl_easy_setopt() and then transfer it
+ with curl_easy_perform(). The handle you get from curl_easy_init() is not
+ only reusable, but you're even encouraged to reuse it if you can, as that
+ will enable libcurl to use persistent connections.
+
+ 5.4 Does libcurl do Winsock initialization on win32 systems?
+
+ Yes, if told to in the curl_global_init() call.
+
+ 5.5 Does CURLOPT_WRITEDATA and CURLOPT_READDATA work on win32 ?
+
+ Yes, but you cannot open a FILE * and pass the pointer to a DLL and have
+ that DLL use the FILE * (as the DLL and the client application cannot access
+ each others' variable memory areas). If you set CURLOPT_WRITEDATA you must
+ also use CURLOPT_WRITEFUNCTION as well to set a function that writes the
+ file, even if that simply writes the data to the specified FILE *.
+ Similarly, if you use CURLOPT_READDATA you must also specify
+ CURLOPT_READFUNCTION.
+
+ 5.6 What about Keep-Alive or persistent connections?
+
+ curl and libcurl have excellent support for persistent connections when
+ transferring several files from the same server. Curl will attempt to reuse
+ connections for all URLs specified on the same command line/config file, and
+ libcurl will reuse connections for all transfers that are made using the
+ same libcurl handle.
+
+ When you use the easy interface, the connection cache is kept within the
+ easy handle. If you instead use the multi interface, the connection cache
+ will be kept within the multi handle and will be shared among all the easy
+ handles that are used within the same multi handle.
+
+ 5.7 Link errors when building libcurl on Windows!
+
+ You need to make sure that your project, and all the libraries (both static
+ and dynamic) that it links against, are compiled/linked against the same run
+ time library.
+
+ This is determined by the /MD, /ML, /MT (and their corresponding /M?d)
+ options to the command line compiler. /MD (linking against MSVCRT dll) seems
+ to be the most commonly used option.
+
+ When building an application that uses the static libcurl library, you must
+ add -DCURL_STATICLIB to your CFLAGS. Otherwise the linker will look for
+ dynamic import symbols. If you're using Visual Studio, you need to instead
+ add CURL_STATICLIB in the "Preprocessor Definitions" section.
+
+ If you get linker error like "unknown symbol __imp__curl_easy_init ..." you
+ have linked against the wrong (static) library. If you want to use the
+ libcurl.dll and import lib, you don't need any extra CFLAGS, but use one of
+ the import libraries below. These are the libraries produced by the various
+ lib/Makefile.* files:
+
+ Target: static lib. import lib for libcurl*.dll.
+ -----------------------------------------------------------
+ MingW: libcurl.a libcurldll.a
+ MSVC (release): libcurl.lib libcurl_imp.lib
+ MSVC (debug): libcurld.lib libcurld_imp.lib
+ Borland: libcurl.lib libcurl_imp.lib
+
+ 5.8 libcurl.so.X: open failed: No such file or directory
+
+ This is an error message you might get when you try to run a program linked
+ with a shared version of libcurl and your run-time linker (ld.so) couldn't
+ find the shared library named libcurl.so.X. (Where X is the number of the
+ current libcurl ABI, typically 3 or 4).
+
+ You need to make sure that ld.so finds libcurl.so.X. You can do that
+ multiple ways, and it differs somewhat between different operating systems,
+ but they are usually:
+
+ * Add an option to the linker command line that specify the hard-coded path
+ the run-time linker should check for the lib (usually -R)
+
+ * Set an environment variable (LD_LIBRARY_PATH for example) where ld.so
+ should check for libs
+
+ * Adjust the system's config to check for libs in the directory where you've
+ put the dir (like Linux's /etc/ld.so.conf)
+
+ 'man ld.so' and 'man ld' will tell you more details
+
+ 5.9 How does libcurl resolve host names?
+
+ libcurl supports a large a number of different name resolve functions. One
+ of them is picked at build-time and will be used unconditionally. Thus, if
+ you want to change name resolver function you must rebuild libcurl and tell
+ it to use a different function.
+
+ - The non-ipv6 resolver that can use one out of four host name resolve calls
+ (depending on what your system supports):
+
+ A - gethostbyname()
+ B - gethostbyname_r() with 3 arguments
+ C - gethostbyname_r() with 5 arguments
+ D - gethostbyname_r() with 6 arguments
+
+ - The ipv6-resolver that uses getaddrinfo()
+
+ - The c-ares based name resolver that uses the c-ares library for resolves.
+ Using this offers asynchronous name resolves.
+
+ - The threaded resolver (default option on Windows). It uses:
+
+ A - gethostbyname() on plain ipv4 hosts
+ B - getaddrinfo() on ipv6-enabled hosts
+
+ Also note that libcurl never resolves or reverse-lookups addresses given as
+ pure numbers, such as 127.0.0.1 or ::1.
+
+ 5.10 How do I prevent libcurl from writing the response to stdout?
+
+ libcurl provides a default built-in write function that writes received data
+ to stdout. Set the CURLOPT_WRITEFUNCTION to receive the data, or possibly
+ set CURLOPT_WRITEDATA to a different FILE * handle.
+
+ 5.11 How do I make libcurl not receive the whole HTTP response?
+
+ You make the write callback (or progress callback) return an error and
+ libcurl will then abort the transfer.
+
+ 5.12 Can I make libcurl fake or hide my real IP address?
+
+ 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. You may also consider using
+ http://www.torproject.org .
+
+ 5.13 How do I stop an ongoing transfer?
+
+ With the easy interface you make sure to return the correct error code from
+ one of the callbacks, but none of them are instant. There is no function you
+ can call from another thread or similar that will stop it immediately.
+ Instead, you need to make sure that one of the callbacks you use returns an
+ appropriate value that will stop the transfer. Suitable callbacks that you
+ can do this with include the progress callback, the read callback and the
+ write callback.
+
+ If you're using the multi interface, you can also stop a transfer by
+ removing the particular easy handle from the multi stack at any moment you
+ think the transfer is done or when you wish to abort the transfer.
+
+ 5.14 Using C++ non-static functions for callbacks?
+
+ libcurl is a C library, it doesn't know anything about C++ member functions.
+
+ You can overcome this "limitation" with a relative ease using a static
+ member function that is passed a pointer to the class:
+
+ // f is the pointer to your object.
+ static YourClass::func(void *buffer, size_t sz, size_t n, void *f)
+ {
+ // Call non-static member function.
+ static_cast<YourClass*>(f)->nonStaticFunction();
+ }
+
+ // This is how you pass pointer to the static function:
+ curl_easy_setopt(hcurl, CURLOPT_WRITEFUNCTION, YourClass:func);
+ curl_easy_setopt(hcurl, CURLOPT_WRITEDATA, this);
+
+ 5.15 How do I get an FTP directory listing?
+
+ If you end the FTP URL you request with a slash, libcurl will provide you
+ with a directory listing of that given directory. You can also set
+ CURLOPT_CUSTOMREQUEST to alter what exact listing command libcurl would use
+ to list the files.
+
+ The follow-up question that tend to follow the previous one, is how a
+ program is supposed to parse the directory listing. How does it know what's
+ a file and what's a dir and what's a symlink etc. The harsh reality is that
+ FTP provides no such fine and easy-to-parse output. The output format FTP
+ servers respond to LIST commands are entirely at the server's own liking and
+ the NLST output doesn't reveal any types and in many cases don't even
+ include all the directory entries. Also, both LIST and NLST tend to hide
+ unix-style hidden files (those that start with a dot) by default so you need
+ to do "LIST -a" or similar to see them.
+
+ The application thus needs to parse the LIST output. One such existing
+ list parser is available at http://cr.yp.to/ftpparse.html Versions of
+ libcurl since 7.21.0 also provide the ability to specify a wildcard to
+ download multiple files from one FTP directory.
+
+ 5.16 I want a different time-out!
+
+ Time and time again users realize that CURLOPT_TIMEOUT and
+ CURLOPT_CONNECTIMEOUT are not sufficiently advanced or flexible to cover all
+ the various use cases and scenarios applications end up with.
+
+ libcurl offers many more ways to time-out operations. A common alternative
+ is to use the CURLOPT_LOW_SPEED_LIMIT and CURLOPT_LOW_SPEED_TIME options to
+ specify the lowest possible speed to accept before to consider the transfer
+ timed out.
+
+ The most flexible way is by writing your own time-out logic and using
+ CURLOPT_PROGRESSFUNCTION (perhaps in combination with other callbacks) and
+ use that to figure out exactly when the right condition is met when the
+ transfer should get stopped.
+
+ 5.17 Can I write a server with libcurl?
+
+ No. libcurl offers no functions or building blocks to build any kind of
+ internet protocol server. libcurl is only a client-side library. For server
+ libraries, you need to continue your search elsewhere but there exist many
+ good open source ones out there for most protocols you could possibly want a
+ server for. And there are really good stand-alone ones that have been tested
+ and proven for many years. There's no need for you to reinvent them!
+
+
+6. License Issues
+
+ Curl and libcurl are released under a MIT/X derivate license. The license is
+ very liberal and should not impose a problem for your project. This section
+ is just a brief summary for the cases we get the most questions. (Parts of
+ this section was much enhanced by Bjorn Reese.)
+
+ We are not lawyers and this is not legal advice. You should probably consult
+ one if you want true and accurate legal insights without our prejudice. Note
+ especially that this section concerns the libcurl license only; compiling in
+ features of libcurl that depend on other libraries (e.g. OpenSSL) may affect
+ the licensing obligations of your application.
+
+ 6.1 I have a GPL program, can I use the libcurl library?
+
+ Yes!
+
+ Since libcurl may be distributed under the MIT/X derivate license, it can be
+ used together with GPL in any software.
+
+ 6.2 I have a closed-source program, can I use the libcurl library?
+
+ Yes!
+
+ libcurl does not put any restrictions on the program that uses the library.
+
+ 6.3 I have a BSD licensed program, can I use the libcurl library?
+
+ Yes!
+
+ libcurl does not put any restrictions on the program that uses the library.
+
+ 6.4 I have a program that uses LGPL libraries, can I use libcurl?
+
+ Yes!
+
+ The LGPL license doesn't clash with other licenses.
+
+ 6.5 Can I modify curl/libcurl for my program and keep the changes secret?
+
+ Yes!
+
+ The MIT/X derivate license practically allows you to do almost anything with
+ the sources, on the condition that the copyright texts in the sources are
+ left intact.
+
+ 6.6 Can you please change the curl/libcurl license to XXXX?
+
+ No.
+
+ We have carefully picked this license after years of development and
+ discussions and a large amount of people have contributed with source code
+ knowing that this is the license we use. This license puts the restrictions
+ we want on curl/libcurl and it does not spread to other programs or
+ libraries that use it. It should be possible for everyone to use libcurl or
+ curl in their projects, no matter what license they already have in use.
+
+ 6.7 What are my obligations when using libcurl in my commercial apps?
+
+ Next to none. All you need to adhere to is the MIT-style license (stated in
+ the COPYING file) which basically says you have to include the copyright
+ notice in "all copies" and that you may not use the copyright holder's name
+ when promoting your software.
+
+ You do not have to release any of your source code.
+
+ You do not have to reveal or make public any changes to the libcurl source
+ code.
+
+ You do not have to broadcast to the world that you are using libcurl within
+ your app.
+
+ All we ask is that you disclose "the copyright notice and this permission
+ notice" somewhere. Most probably like in the documentation or in the section
+ where other third party dependencies already are mentioned and acknowledged.
+
+ As can be seen here: http://curl.haxx.se/docs/companies.html and elsewhere,
+ more and more companies are discovering the power of libcurl and take
+ advantage of it even in commercial environments.
+
+
+7. PHP/CURL Issues
+
+ 7.1 What is PHP/CURL?
+
+ The module for PHP that makes it possible for PHP programs to access curl-
+ functions from within PHP.
+
+ In the cURL project we call this module PHP/CURL to differentiate it from
+ curl the command line tool and libcurl the library. The PHP team however
+ does not refer to it like this (for unknown reasons). They call it plain
+ CURL (often using all caps) or sometimes ext/curl, but both cause much
+ confusion to users which in turn gives us a higher question load.
+
+ 7.2 Who wrote PHP/CURL?
+
+ PHP/CURL is a module that comes with the regular PHP package. It depends and
+ uses libcurl, so you need to have libcurl installed properly first before
+ PHP/CURL can be used. PHP/CURL was initially written by Sterling Hughes.
+
+ 7.3 Can I perform multiple requests using the same handle?
+
+ Yes - at least in PHP version 4.3.8 and later (this has been known to not
+ work in earlier versions, but the exact version when it started to work is
+ unknown to me).
+
+ After a transfer, you just set new options in the handle and make another
+ transfer. This will make libcurl to re-use the same connection if it can.
diff --git a/libs/libcurl/docs/FEATURES b/libs/libcurl/docs/FEATURES
new file mode 100644
index 0000000000..14d7e78ddb
--- /dev/null
+++ b/libs/libcurl/docs/FEATURES
@@ -0,0 +1,196 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+FEATURES
+
+curl tool
+ - config file support
+ - multiple URLs in a single command line
+ - range "globbing" support: [0-13], {one,two,three}
+ - multiple file upload on a single command line
+ - custom maximum transfer rate
+ - redirectable stderr
+ - metalink support (*13)
+
+libcurl
+ - full URL syntax with no length limit
+ - custom maximum download time
+ - custom least download speed acceptable
+ - custom output result after completion
+ - guesses protocol from host name unless specified
+ - uses .netrc
+ - progress bar with time statistics while downloading
+ - "standard" proxy environment variables support
+ - compiles on win32 (reported builds on 40+ operating systems)
+ - selectable network interface for outgoing traffic
+ - IPv6 support on unix and Windows
+ - persistent connections
+ - socks5 support
+ - supports user name and password in proxy environment variables
+ - operations through proxy "tunnel" (using CONNECT)
+ - support for large files (>2GB and >4GB) during upload and download
+ - replaceable memory functions (malloc, free, realloc, etc)
+ - asynchronous name resolving (*6)
+ - both a push and a pull style interface
+ - international domain names (*11)
+
+HTTP
+ - HTTP/1.1 compliant (optionally uses 1.0)
+ - GET
+ - PUT
+ - HEAD
+ - POST
+ - Pipelining
+ - multipart formpost (RFC1867-style)
+ - authentication: Basic, Digest, NTLM (*9), GSS-Negotiate/Negotiate (*3) and
+ SPNEGO (*4) to server and proxy
+ - resume (both GET and PUT)
+ - follow redirects
+ - maximum amount of redirects to follow
+ - custom HTTP request
+ - cookie get/send fully parsed
+ - reads/writes the netscape cookie file format
+ - custom headers (replace/remove internally generated headers)
+ - custom user-agent string
+ - custom referer string
+ - range
+ - proxy authentication
+ - time conditions
+ - via http-proxy
+ - retrieve file modification date
+ - Content-Encoding support for deflate and gzip
+ - "Transfer-Encoding: chunked" support in uploads
+ - data compression (*12)
+
+HTTPS (*1)
+ - (all the HTTP features)
+ - using client certificates
+ - verify server certificate
+ - via http-proxy
+ - select desired encryption
+ - force usage of a specific SSL version (SSLv2 (*7), SSLv3 (*10) or TLSv1)
+
+FTP
+ - download
+ - authentication
+ - kerberos4 (*5)
+ - kerberos5 (*3)
+ - active/passive using PORT, EPRT, PASV or EPSV
+ - single file size information (compare to HTTP HEAD)
+ - 'type=' URL support
+ - dir listing
+ - dir listing names-only
+ - upload
+ - upload append
+ - upload via http-proxy as HTTP PUT
+ - download resume
+ - upload resume
+ - custom ftp commands (before and/or after the transfer)
+ - simple "range" support
+ - via http-proxy
+ - all operations can be tunneled through a http-proxy
+ - customizable to retrieve file modification date
+ - no dir depth limit
+
+FTPS (*1)
+ - implicit ftps:// support that use SSL on both connections
+ - explicit "AUTH TLS" and "AUTH SSL" usage to "upgrade" plain ftp://
+ connection to use SSL for both or one of the connections
+
+SCP (*8)
+ - both password and public key auth
+
+SFTP (*8)
+ - both password and public key auth
+ - with custom commands sent before/after the transfer
+
+TFTP
+ - download
+ - upload
+
+TELNET
+ - connection negotiation
+ - custom telnet options
+ - stdin/stdout I/O
+
+LDAP (*2)
+ - full LDAP URL support
+
+DICT
+ - extended DICT URL support
+
+FILE
+ - URL support
+ - upload
+ - resume
+
+SMTP
+ - authentication: Plain, Login, CRAM-MD5, Digest-MD5 and NTLM (*9)
+ - send e-mails
+ - mail from support
+ - mail size support
+ - mail auth support for trusted server-to-server relaying
+ - multiple recipients
+ - via http-proxy
+
+SMTPS (*1)
+ - implicit smtps:// support
+ - explicit "STARTTLS" usage to "upgrade" plain smtp:// connections to use SSL
+ - via http-proxy
+
+POP3
+ - authentication: Clear Text, APOP and SASL
+ - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5 and
+ NTLM (*9)
+ - list e-mails
+ - retrieve e-mails
+ - enhanced command support for: CAPA, DELE, TOP, STAT, UIDL and NOOP via
+ custom requests
+ - via http-proxy
+
+POP3S (*1)
+ - implicit pop3s:// support
+ - explicit "STLS" usage to "upgrade" plain pop3:// connections to use SSL
+ - via http-proxy
+
+IMAP
+ - authentication: Clear Text and SASL
+ - SASL based authentication: Plain, Login, CRAM-MD5, Digest-MD5 and
+ NTLM (*9)
+ - list the folders of a mailbox
+ - select a mailbox with support for verifing the UIDVALIDITY
+ - fetch e-mails with support for specifing the UID and SECTION
+ - upload e-mails via the append command
+ - enhanced command support for: EXAMINE, CREATE, DELETE, RENAME, STATUS,
+ STORE, COPY and UID via custom requests
+ - via http-proxy
+
+IMAPS (*1)
+ - implicit imaps:// support
+ - explicit "STARTTLS" usage to "upgrade" plain imap:// connections to use SSL
+ - via http-proxy
+
+FOOTNOTES
+=========
+
+ *1 = requires OpenSSL, GnuTLS, NSS, yassl, axTLS, PolarSSL, schannel (native
+ Windows), Secure Transport (native iOS/OS X) or qssl (native IBM i)
+ *2 = requires OpenLDAP
+ *3 = requires a GSSAPI-compliant library, such as Heimdal or similar
+ *4 = requires FBopenssl
+ *5 = requires a krb4 library, such as the MIT one or similar
+ *6 = requires c-ares
+ *7 = requires OpenSSL, NSS, qssl, schannel or Secure Transport; GnuTLS, for
+ example, only supports SSLv3 and TLSv1
+ *8 = requires libssh2
+ *9 = requires OpenSSL, GnuTLS, NSS, yassl, Secure Transport or SSPI (native
+ Windows)
+ *10 = requires any of the SSL libraries in (*1) above other than axTLS, which
+ does not support SSLv3
+ *11 = requires libidn or Windows
+ *12 = requires libz
+ *13 = requires libmetalink, and either an Apple or Microsoft operating
+ system, or OpenSSL, or GnuTLS, or NSS
diff --git a/libs/libcurl/docs/HISTORY b/libs/libcurl/docs/HISTORY
new file mode 100644
index 0000000000..3c140999ec
--- /dev/null
+++ b/libs/libcurl/docs/HISTORY
@@ -0,0 +1,244 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ How cURL Became Like This
+
+
+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 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.
+
+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,
+1998 curl 4 was released. (The version numbering from the previous names was
+kept.)
+
+(Unrelated to this project a company called Curl Corporation registered a US
+trademark on the name "CURL" on May 18 1998. That company had then already
+registered the curl.com domain back in November of the previous year. All this
+was revealed to us much later.)
+
+SSL support was added, powered by the SSLeay library.
+
+August 1998, first announcement of curl on freshmeat.net.
+
+October 1998, with the curl 4.9 release and the introduction of cookie
+support, curl was no longer released under the GPL license. Now we're at 4000
+lines of code, we switched over to the MPL license to restrict the effects of
+"copyleft".
+
+November 1998, configure script and reported successful compiles on several
+major operating systems. The never-quite-understood -F option was added and
+curl could now simulate quite a lot of a browser. TELNET support was added.
+
+Curl 5 was released in December 1998 and introduced the first ever curl man
+page. People started making Linux RPM packages out of it.
+
+January 1999, DICT support added.
+
+OpenSSL took over where SSLeay was abandoned.
+
+May 1999, first Debian package.
+
+August 1999, LDAP:// and FILE:// support added. The curl web site gets 1300
+visits weekly.
+
+Released curl 6.0 in September. 15000 lines of code.
+
+December 28 1999, added the project on Sourceforge and started using its
+services for managing the project.
+
+Spring 2000, major internal overhaul to provide a suitable library interface.
+The first non-beta release was named 7.1 and arrived in August. This offered
+the easy interface and turned out to be the beginning of actually getting
+other software and programs to get based on and powered by libcurl. Almost
+20000 lines of code.
+
+August 2000, the curl web site gets 4000 visits weekly.
+
+The PHP guys adopted libcurl already the same month, when the first ever third
+party libcurl binding showed up. CURL has been a supported module in PHP since
+the release of PHP 4.0.2. This would soon get followers. More than 16
+different bindings exist at the time of this writing.
+
+September 2000, kerberos4 support was added.
+
+In November 2000 started the work on a test suite for curl. It was later
+re-written from scratch again. The libcurl major SONAME number was set to 1.
+
+January 2001, Daniel released curl 7.5.2 under a new license again: MIT (or
+MPL). The MIT license is extremely liberal and can be used combined with GPL
+in other projects. This would finally put an end to the "complaints" from
+people involved in GPLed projects that previously were prohibited from using
+libcurl while it was released under MPL only. (Due to the fact that MPL is
+deemed "GPL incompatible".)
+
+curl supports HTTP 1.1 starting with the release of 7.7, March 22 2001. This
+also introduced libcurl's ability to do persistent connections. 24000 lines of
+code. The libcurl major SONAME number was bumped to 2 due to this overhaul.
+
+The first experimental ftps:// support was added in March 2001.
+
+August 2001. curl is bundled in Mac OS X, 10.1. It was already becoming more
+and more of a standard utility of Linux distributions and a regular in the BSD
+ports collections. The curl web site gets 8000 visits weekly. Curl Corporation
+contacted Daniel to discuss "the name issue". After Daniel's reply, they have
+never since got in touch again.
+
+September 2001, libcurl 7.9 introduces cookie jar and curl_formadd(). During
+the forthcoming 7.9.x releases, we introduced the multi interface slowly and
+without much whistles.
+
+June 2002, the curl web site gets 13000 visits weekly. curl and libcurl is
+35000 lines of code. Reported successful compiles on more than 40 combinations
+of CPUs and operating systems.
+
+To estimate number of users of the curl tool or libcurl library is next to
+impossible. Around 5000 downloaded packages each week from the main site gives
+a hint, but the packages are mirrored extensively, bundled with numerous OS
+distributions and otherwise retrieved as part of other software.
+
+September 2002, with the release of curl 7.10 it is released under the MIT
+license only.
+
+January 2003. Started working on the distributed curl tests. The autobuilds.
+
+February 2003, the curl site averages at 20000 visits weekly. At any given
+moment, there's an average of 3 people browsing the curl.haxx.se site.
+
+Multiple new authentication schemes are supported: Digest (May), NTLM (June)
+and Negotiate (June).
+
+November 2003: curl 7.10.8 is released. 45000 lines of code. ~55000 unique
+visitors to the curl.haxx.se site. Five official web mirrors.
+
+December 2003, full-fledged SSL for FTP is supported.
+
+January 2004: curl 7.11.0 introduced large file support.
+
+June 2004:
+
+ curl 7.12.0 introduced IDN support. 10 official web mirrors.
+
+ This release bumped the major SONAME to 3 due to the removal of the
+ curl_formparse() function
+
+August 2004:
+ Curl and libcurl 7.12.1
+
+ Public curl release number: 82
+ Releases counted from the very beginning: 109
+ Available command line options: 96
+ Available curl_easy_setopt() options: 120
+ Number of public functions in libcurl: 36
+ Amount of public web site mirrors: 12
+ Number of known libcurl bindings: 26
+
+April 2005:
+
+ GnuTLS can now optionally be used for the secure layer when curl is built.
+
+September 2005:
+
+ TFTP support was added.
+
+ More than 100,000 unique visitors of the curl web site. 25 mirrors.
+
+December 2005:
+
+ security vulnerability: libcurl URL Buffer Overflow
+
+January 2006:
+
+ We dropped support for Gopher. We found bugs in the implementation that
+ turned out having been introduced years ago, so with the conclusion that
+ nobody had found out in all this time we removed it instead of fixing it.
+
+March 2006:
+
+ security vulnerability: libcurl TFTP Packet Buffer Overflow
+
+April 2006:
+
+ Added the multi_socket() API
+
+September 2006:
+
+ The major SONAME number for libcurl was bumped to 4 due to the removal of
+ ftp third party transfer support.
+
+November 2006:
+
+ Added SCP and SFTP support
+
+February 2007:
+
+ Added support for the Mozilla NSS library to do the SSL/TLS stuff
+
+July 2007:
+
+ security vulnerability: libcurl GnuTLS insufficient cert verification
+
+November 2008:
+
+ Command line options: 128
+ curl_easy_setopt() options: 158
+ Public functions in libcurl: 58
+ Known libcurl bindings: 37
+ Contributors: 683
+
+ 145,000 unique visitors. >100 GB downloaded.
+
+March 2009:
+
+ security vulnerability: libcurl Arbitrary File Access
+
+August 2009:
+
+ security vulnerability: libcurl embedded zero in cert name
+
+December 2009:
+
+ Added support for IMAP, POP3 and SMTP
+
+January 2010:
+
+ Added support for RTSP
+
+February 2010:
+
+ security vulnerability: libcurl data callback excessive length
+
+March 2010:
+
+ The project switched over to use git instead of CVS for source code control
+
+May 2010:
+
+ Added support for RTMP
+
+ Added support for PolarSSL to do the SSL/TLS stuff
+
+August 2010:
+
+ Public curl releases: 117
+ Command line options: 138
+ curl_easy_setopt() options: 180
+ Public functions in libcurl: 58
+ Known libcurl bindings: 39
+ Contributors: 808
+
+ Gopher support added (re-added actually)
diff --git a/libs/libcurl/docs/HTTP-COOKIES b/libs/libcurl/docs/HTTP-COOKIES
new file mode 100644
index 0000000000..818e161eef
--- /dev/null
+++ b/libs/libcurl/docs/HTTP-COOKIES
@@ -0,0 +1,123 @@
+Updated: July 3, 2012 (http://curl.haxx.se/docs/http-cookies.html)
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+
+HTTP Cookies
+
+ 1. HTTP Cookies
+ 1.1 Cookie overview
+ 1.2 Cookies saved to disk
+ 1.3 Cookies with curl the command line tool
+ 1.4 Cookies with libcurl
+ 1.5 Cookies with javascript
+
+==============================================================================
+
+1. HTTP Cookies
+
+ 1.1 Cookie overview
+
+ HTTP cookies are pieces of 'name=contents' snippets that a server tells the
+ client to hold and then the client sends back those the server on subsequent
+ requests to the same domains/paths for which the cookies were set.
+
+ Cookies are either "session cookies" which typically are forgotten when the
+ session is over which is often translated to equal when browser quits, or
+ the cookies aren't session cookies they have expiration dates after which
+ the client will throw them away.
+
+ Cookies are set to the client with the Set-Cookie: header and are sent to
+ servers with the Cookie: header.
+
+ For a very long time, the only spec explaining how to use cookies was the
+ original Netscape spec from 1994: http://curl.haxx.se/rfc/cookie_spec.html
+
+ In 2011, RFC6265 (http://www.ietf.org/rfc/rfc6265.txt) was finally published
+ and details how cookies work within HTTP.
+
+ 1.2 Cookies saved to disk
+
+ Netscape once created a file format for storing cookies on disk so that they
+ would survive browser restarts. curl adopted that file format to allow
+ sharing the cookies with browsers, only to see browsers move away from that
+ format. Modern browsers no longer use it, while curl still does.
+
+ The netscape cookie file format stores one cookie per physical line in the
+ file with a bunch of associated meta data, each field separated with
+ TAB. That file is called the cookiejar in curl terminology.
+
+ When libcurl saves a cookiejar, it creates a file header of its own in which
+ there is a URL mention that will link to the web version of this document.
+
+ 1.3 Cookies with curl the command line tool
+
+ curl has a full cookie "engine" built in. If you just activate it, you can
+ have curl receive and send cookies exactly as mandated in the specs.
+
+ Command line options:
+
+ -b, --cookie
+
+ tell curl a file to read cookies from and start the cookie engine, or if
+ it isn't a file it will pass on the given string. -b name=var works and so
+ does -b cookiefile.
+
+ -j, --junk-session-cookies
+
+ when used in combination with -b, it will skip all "session cookies" on
+ load so as to appear to start a new cookie session.
+
+ -c, --cookie-jar
+
+ tell curl to start the cookie engine and write cookies to the given file
+ after the request(s)
+
+ 1.4 Cookies with libcurl
+
+ libcurl offers several ways to enable and interface the cookie engine. These
+ options are the ones provided by the native API. libcurl bindings may offer
+ access to them using other means.
+
+ CURLOPT_COOKIE
+
+ Is used when you want to specify the exact contents of a cookie header to
+ send to the server.
+
+ CURLOPT_COOKIEFILE
+
+ Tell libcurl to activate the cookie engine, and to read the initial set of
+ cookies from the given file. Read-only.
+
+ CURLOPT_COOKIEJAR
+
+ Tell libcurl to activate the cookie engine, and when the easy handle is
+ closed save all known cookies to the given cookiejar file. Write-only.
+
+ CURLOPT_COOKIELIST
+
+ Provide detailed information about a single cookie to add to the internal
+ storage of cookies. Pass in the cookie as a HTTP header with all the
+ details set, or pass in a line from a netscape cookie file. This option
+ can also be used to flush the cookies etc.
+
+ CURLINFO_COOKIELIST
+
+ Extract cookie information from the internal cookie storage as a linked
+ list.
+
+ 1.5 Cookies with javascript
+
+ These days a lot of the web is built up by javascript. The webbrowser loads
+ complete programs that render the page you see. These javascript programs
+ can also set and access cookies.
+
+ Since curl and libcurl are plain HTTP clients without any knowledge of or
+ capability to handle javascript, such cookies will not be detected or used.
+
+ Often, if you want to mimic what a browser does on such web sites, you can
+ record web browser HTTP traffic when using such a site and then repeat the
+ cookie operations using curl or libcurl.
diff --git a/libs/libcurl/docs/INSTALL b/libs/libcurl/docs/INSTALL
new file mode 100644
index 0000000000..4140359dad
--- /dev/null
+++ b/libs/libcurl/docs/INSTALL
@@ -0,0 +1,1131 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ How To Compile
+
+Installing Binary Packages
+==========================
+
+ Lots of people download binary distributions of curl and libcurl. This
+ document does not describe how to install curl or libcurl using such a
+ binary package. This document describes how to compile, build and install
+ curl and libcurl from source code.
+
+Building from git
+=================
+
+ If you get your code off a git repository, see the GIT-INFO file in the
+ root directory for specific instructions on how to proceed.
+
+UNIX
+====
+ A normal unix installation is made in three or four steps (after you've
+ unpacked the source archive):
+
+ ./configure
+ make
+ make test (optional)
+ make install
+
+ You probably need to be root when doing the last command.
+
+ If you have checked out the sources from the git repository, read the
+ GIT-INFO on how to proceed.
+
+ Get a full listing of all available configure options by invoking it like:
+
+ ./configure --help
+
+ If you want to install curl in a different file hierarchy than /usr/local,
+ you need to specify that already when running configure:
+
+ ./configure --prefix=/path/to/curl/tree
+
+ If you happen to have write permission in that directory, you can do 'make
+ install' without being root. An example of this would be to make a local
+ install in your own home directory:
+
+ ./configure --prefix=$HOME
+ make
+ make install
+
+ The configure script always tries to find a working SSL library unless
+ explicitly told not to. If you have OpenSSL installed in the default search
+ path for your compiler/linker, you don't need to do anything special. If
+ you have OpenSSL installed in /usr/local/ssl, you can run configure like:
+
+ ./configure --with-ssl
+
+ If you have OpenSSL installed somewhere else (for example, /opt/OpenSSL)
+ and you have pkg-config installed, set the pkg-config path first, like this:
+
+ env PKG_CONFIG_PATH=/opt/OpenSSL/lib/pkgconfig ./configure --with-ssl
+
+ Without pkg-config installed, use this:
+
+ ./configure --with-ssl=/opt/OpenSSL
+
+ If you insist on forcing a build without SSL support, even though you may
+ have OpenSSL installed in your system, you can run configure like this:
+
+ ./configure --without-ssl
+
+ If you have OpenSSL installed, but with the libraries in one place and the
+ header files somewhere else, you have to set the LDFLAGS and CPPFLAGS
+ environment variables prior to running configure. Something like this
+ should work:
+
+ (with the Bourne shell and its clones):
+
+ CPPFLAGS="-I/path/to/ssl/include" LDFLAGS="-L/path/to/ssl/lib" \
+ ./configure
+
+ (with csh, tcsh and their clones):
+
+ env CPPFLAGS="-I/path/to/ssl/include" LDFLAGS="-L/path/to/ssl/lib" \
+ ./configure
+
+ If you have shared SSL libs installed in a directory where your run-time
+ linker doesn't find them (which usually causes configure failures), you can
+ provide the -R option to ld on some operating systems to set a hard-coded
+ path to the run-time linker:
+
+ env LDFLAGS=-R/usr/local/ssl/lib ./configure --with-ssl
+
+ MORE OPTIONS
+ ------------
+
+ To force configure to use the standard cc compiler if both cc and gcc are
+ present, run configure like
+
+ CC=cc ./configure
+ or
+ env CC=cc ./configure
+
+ To force a static library compile, disable the shared library creation
+ by running configure like:
+
+ ./configure --disable-shared
+
+ To tell the configure script to skip searching for thread-safe functions,
+ add an option like:
+
+ ./configure --disable-thread
+
+ To build curl with kerberos4 support enabled, curl requires the krb4 libs
+ and headers installed. You can then use a set of options to tell
+ configure where those are:
+
+ --with-krb4-includes[=DIR] Specify location of kerberos4 headers
+ --with-krb4-libs[=DIR] Specify location of kerberos4 libs
+ --with-krb4[=DIR] where to look for Kerberos4
+
+ In most cases, /usr/athena is the install prefix and then it works with
+
+ ./configure --with-krb4=/usr/athena
+
+ If you're a curl developer and use gcc, you might want to enable more
+ debug options with the --enable-debug option.
+
+ curl can be built to use a whole range of libraries to provide various
+ useful services, and configure will try to auto-detect a decent
+ default. But if you want to alter it, you can select how to deal with
+ each individual library.
+
+ To build with GnuTLS for SSL/TLS, use both --without-ssl and
+ --with-gnutls.
+
+ To build with Cyassl for SSL/TLS, use both --without-ssl and
+ --with-cyassl.
+
+ To build with NSS for SSL/TLS, use both --without-ssl and --with-nss.
+
+ To build with PolarSSL for SSL/TLS, use both --without-ssl and
+ --with-polarssl.
+
+ To build with axTLS for SSL/TLS, use both --without-ssl and --with-axtls.
+
+ To get GSSAPI support, build with --with-gssapi and have the MIT or
+ Heimdal Kerberos 5 packages installed.
+
+ To get support for SCP and SFTP, build with --with-libssh2 and have
+ libssh2 0.16 or later installed.
+
+ To get Metalink support, build with --with-libmetalink and have the
+ libmetalink packages installed.
+
+ SPECIAL CASES
+ -------------
+ Some versions of uClibc require configuring with CPPFLAGS=-D_GNU_SOURCE=1
+ to get correct large file support.
+
+ The Open Watcom C compiler on Linux requires configuring with the variables:
+
+ ./configure CC=owcc AR="$WATCOM/binl/wlib" AR_FLAGS=-q \
+ RANLIB=/bin/true STRIP="$WATCOM/binl/wstrip" CFLAGS=-Wextra
+
+
+Win32
+=====
+
+ Building Windows DLLs and C run-time (CRT) linkage issues
+ ---------------------------------------------------------
+
+ As a general rule, building a DLL with static CRT linkage is highly
+ discouraged, and intermixing CRTs in the same app is something to
+ avoid at any cost.
+
+ Reading and comprehension of Microsoft Knowledge Base articles
+ KB94248 and KB140584 is a must for any Windows developer. Especially
+ important is full understanding if you are not going to follow the
+ advice given above.
+
+ KB94248 - How To Use the C Run-Time
+ http://support.microsoft.com/kb/94248/en-us
+
+ KB140584 - How to link with the correct C Run-Time (CRT) library
+ http://support.microsoft.com/kb/140584/en-us
+
+ KB190799 - Potential Errors Passing CRT Objects Across DLL Boundaries
+ http://msdn.microsoft.com/en-us/library/ms235460
+
+ If your app is misbehaving in some strange way, or it is suffering
+ from memory corruption, before asking for further help, please try
+ first to rebuild every single library your app uses as well as your
+ app using the debug multithreaded dynamic C runtime.
+
+ If you get linkage errors read section 5.7 of the FAQ document.
+
+
+ MingW32
+ -------
+
+ Make sure that MinGW32's bin dir is in the search path, for example:
+
+ set PATH=c:\mingw32\bin;%PATH%
+
+ then run 'mingw32-make mingw32' in the root dir. There are other
+ make targets available to build libcurl with more features, use:
+ 'mingw32-make mingw32-zlib' to build with Zlib support;
+ 'mingw32-make mingw32-ssl-zlib' to build with SSL and Zlib enabled;
+ 'mingw32-make mingw32-ssh2-ssl-zlib' to build with SSH2, SSL, Zlib;
+ 'mingw32-make mingw32-ssh2-ssl-sspi-zlib' to build with SSH2, SSL, Zlib
+ and SSPI support.
+
+ If you have any problems linking libraries or finding header files, be sure
+ to verify that the provided "Makefile.m32" files use the proper paths, and
+ adjust as necessary. It is also possible to override these paths with
+ environment variables, for example:
+
+ set ZLIB_PATH=c:\zlib-1.2.8
+ set OPENSSL_PATH=c:\openssl-0.9.8y
+ set LIBSSH2_PATH=c:\libssh2-1.4.3
+
+ ATTENTION: if you want to build with libssh2 support you have to use latest
+ version 0.17 - previous versions will NOT work with 7.17.0 and later!
+ Use 'mingw32-make mingw32-ssh2-ssl-zlib' to build with SSH2 and SSL enabled.
+
+ It is now also possible to build with other LDAP SDKs than MS LDAP;
+ currently it is possible to build with native Win32 OpenLDAP, or with the
+ Novell CLDAP SDK. If you want to use these you need to set these vars:
+
+ set LDAP_SDK=c:\openldap
+ set USE_LDAP_OPENLDAP=1
+
+ or for using the Novell SDK:
+
+ set USE_LDAP_NOVELL=1
+
+ If you want to enable LDAPS support then set LDAPS=1.
+
+ - optional MingW32-built OpenLDAP SDK available from:
+ http://www.gknw.net/mirror/openldap/
+ - optional recent Novell CLDAP SDK available from:
+ http://developer.novell.com/ndk/cldap.htm
+
+
+ Cygwin
+ ------
+
+ Almost identical to the unix installation. Run the configure script in the
+ curl root with 'sh configure'. Make sure you have the sh executable in
+ /bin/ or you'll see the configure fail toward the end.
+
+ Run 'make'
+
+ Dev-Cpp
+ -------
+
+ See the separate INSTALL.devcpp file for details.
+
+ MSVC 6 caveats
+ --------------
+
+ If you use MSVC 6 it is required that you use the February 2003 edition PSDK:
+ http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
+
+ Building any software with MSVC 6 without having PSDK installed is just
+ asking for trouble down the road once you have released it, you might notice
+ the problems in the first corner or ten miles ahead, depending mostly on your
+ choice of static vs dynamic runtime and third party libraries. Anyone using
+ software built in such way will at some point regret having done so.
+
+ When someone uses MSVC 6 without PSDK he is using a compiler back from 1998.
+
+ If the compiler has been updated with the installation of a service pack as
+ those mentioned in http://support.microsoft.com/kb/194022 the compiler can be
+ safely used to read source code, translate and make it object code.
+
+ But, even with the service packs mentioned above installed, the resulting
+ software generated in such an environment will be using outdated system
+ header files and libraries with bugs and security issues which have already
+ been addressed and fixed long time ago.
+
+ In order to make use of the updated system headers and fixed libraries
+ for MSVC 6, it is required that 'Platform SDK', PSDK from now onwards,
+ is installed. The specific PSDK that must be installed for MSVC 6 is the
+ February 2003 edition, which is the latest one supporting the MSVC 6 compiler,
+ this PSDK is also known as 'Windows Server 2003 PSDK' and can be downloaded
+ from http://www.microsoft.com/msdownload/platformsdk/sdkupdate/psdk-full.htm
+
+ So, building curl and libcurl with MSVC 6 without PSDK is absolutely
+ discouraged for the benefit of anyone using software built in such
+ environment. And it will not be supported in any way, as we could just
+ be hunting bugs which have already been fixed way back in 2003.
+
+ When building with MSVC 6 we attempt to detect if PSDK is not being used,
+ and if this is the case the build process will fail hard with an error
+ message stating that the February 2003 PSDK is required. This is done to
+ protect the unsuspecting and avoid PEBKAC issues.
+
+ Additionally it might happen that a die hard MSVC hacker still wants to
+ build curl and libcurl with MSVC 6 without PSDK installed, even knowing
+ that this is a highly discouraged and unsupported build environment. In
+ this case the brave of heart will be able to build in such an environment
+ with the requisite of defining preprocessor symbol ALLOW_MSVC6_WITHOUT_PSDK
+ in lib/config-win32.h and knowing that LDAP and IPv6 support will be missing.
+
+ MSVC from command line
+ ----------------------
+
+ Run the 'vcvars32.bat' file to get a proper environment. The
+ vcvars32.bat file is part of the Microsoft development environment and
+ you may find it in 'C:\Program Files\Microsoft Visual Studio\vc98\bin'
+ provided that you installed Visual C/C++ 6 in the default directory.
+
+ Then run 'nmake vc' in curl's root directory.
+
+ If you want to compile with zlib support, you will need to build
+ zlib (http://www.gzip.org/zlib/) as well. Please read the zlib
+ 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.8
+
+ Then run 'nmake vc-zlib' in curl's root directory.
+
+ If you want to compile with SSL support you need the OpenSSL package.
+ Please read the OpenSSL documentation on how to compile and install
+ the OpenSSL libraries. The build process of OpenSSL generates the
+ libeay32.dll and ssleay32.dll files in the out32dll subdirectory in
+ the OpenSSL home directory. OpenSSL static libraries (libeay32.lib,
+ ssleay32.lib, RSAglue.lib) are created in the out32 subdirectory.
+
+ Before running nmake define the OPENSSL_PATH environment variable with
+ the root/base directory of OpenSSL, for example:
+
+ set OPENSSL_PATH=c:\openssl-0.9.8y
+
+ Then run 'nmake vc-ssl' or 'nmake vc-ssl-dll' in curl's root
+ directory. 'nmake vc-ssl' will create a libcurl static and dynamic
+ libraries in the lib subdirectory, as well as a statically linked
+ version of curl.exe in the src subdirectory. This statically linked
+ version is a standalone executable not requiring any DLL at
+ runtime. This make method requires that you have the static OpenSSL
+ libraries available in OpenSSL's out32 subdirectory.
+ 'nmake vc-ssl-dll' creates the libcurl dynamic library and
+ links curl.exe against libcurl and OpenSSL dynamically.
+ This executable requires libcurl.dll and the OpenSSL DLLs
+ at runtime.
+ Run 'nmake vc-ssl-zlib' to build with both ssl and zlib support.
+
+ MSVC 6 IDE
+ ----------
+
+ A minimal VC++ 6.0 reference workspace (vc6curl.dsw) is available with the
+ source distribution archive to allow proper building of the two included
+ projects, the libcurl library and the curl tool.
+
+ 1) Open the vs/vc6/vc6curl.dsw workspace with MSVC6's IDE.
+ 2) Select 'Build' from top menu.
+ 3) Select 'Batch Build' from dropdown menu.
+ 4) Make sure that the eight project configurations are 'checked'.
+ 5) Click on the 'Build' button.
+ 6) Once the eight project configurations are built you are done.
+
+ Dynamic and static libcurl libraries are built in debug and release flavours,
+ and can be located each one in its own subdirectory, dll-debug, dll-release,
+ lib-debug and lib-release, all of them below the 'vs/vc6/lib' subdirectory.
+
+ In the same way four curl executables are created, each using its respective
+ library. The resulting curl executables are located in its own subdirectory,
+ dll-debug, dll-release, lib-debug and lib-release, below 'vs/vc6/src' subdir.
+
+ These reference VC++ 6.0 configurations are generated using the dynamic CRT.
+
+ Intentionally, these reference VC++ 6.0 projects and configurations don't use
+ third party libraries, such as OpenSSL or Zlib, to allow proper compilation
+ and configuration for all new users without further requirements.
+
+ If you need something more 'involved' you might adjust them for your own use,
+ or explore the world of makefiles described above 'MSVC from command line'.
+
+ Borland C++ compiler
+ ---------------------
+
+ Ensure that your build environment is properly set up to use the compiler
+ and associated tools. PATH environment variable must include the path to
+ bin subdirectory of your compiler installation, eg: c:\Borland\BCC55\bin
+
+ It is advisable to set environment variable BCCDIR to the base path of
+ the compiler installation.
+
+ set BCCDIR=c:\Borland\BCC55
+
+ In order to build a plain vanilla version of curl and libcurl run the
+ following command from curl's root directory:
+
+ make borland
+
+ To build curl and libcurl with zlib and OpenSSL support set environment
+ variables ZLIB_PATH and OPENSSL_PATH to the base subdirectories of the
+ already built zlib and OpenSSL libraries and from curl's root directory
+ run command:
+
+ make borland-ssl-zlib
+
+ libcurl library will be built in 'lib' subdirectory while curl tool
+ is built in 'src' subdirectory. In order to use libcurl library it is
+ advisable to modify compiler's configuration file bcc32.cfg located
+ in c:\Borland\BCC55\bin to reflect the location of libraries include
+ paths for example the '-I' line could result in something like:
+
+ -I"c:\Borland\BCC55\include;c:\curl\include;c:\openssl\inc32"
+
+ bcc3.cfg '-L' line could also be modified to reflect the location of
+ of libcurl library resulting for example:
+
+ -L"c:\Borland\BCC55\lib;c:\curl\lib;c:\openssl\out32"
+
+ In order to build sample program 'simple.c' from the docs\examples
+ subdirectory run following command from mentioned subdirectory:
+
+ bcc32 simple.c libcurl.lib cw32mt.lib
+
+ In order to build sample program simplessl.c an SSL enabled libcurl
+ is required, as well as the OpenSSL libeay32.lib and ssleay32.lib
+ libraries.
+
+
+ OTHER MSVC IDEs
+ ---------------
+
+ If you use VC++, Borland or similar compilers. Include all lib source
+ files in a static lib "project" (all .c and .h files that is).
+ (you should name it libcurl or similar)
+
+ Make the sources in the src/ drawer be a "win32 console application"
+ project. Name it curl.
+
+
+ Disabling Specific Protocols in Win32 builds
+ --------------------------------------------
+
+ The configure utility, unfortunately, is not available for the Windows
+ environment, therefore, you cannot use the various disable-protocol
+ options of the configure utility on this platform.
+
+ However, you can use the following defines to disable specific
+ protocols:
+
+ HTTP_ONLY disables all protocols except HTTP
+ CURL_DISABLE_FTP disables FTP
+ CURL_DISABLE_LDAP disables LDAP
+ CURL_DISABLE_TELNET disables TELNET
+ CURL_DISABLE_DICT disables DICT
+ CURL_DISABLE_FILE disables FILE
+ CURL_DISABLE_TFTP disables TFTP
+ CURL_DISABLE_HTTP disables HTTP
+
+ If you want to set any of these defines you have the following
+ possibilities:
+
+ - Modify lib/config-win32.h
+ - Modify lib/curl_setup.h
+ - Modify lib/Makefile.vc6
+ - Add defines to Project/Settings/C/C++/General/Preprocessor Definitions
+ in the vc6libcurl.dsw/vc6libcurl.dsp Visual C++ 6 IDE project.
+
+
+ Using BSD-style lwIP instead of Winsock TCP/IP stack in Win32 builds
+ --------------------------------------------------------------------
+
+ In order to compile libcurl and curl using BSD-style lwIP TCP/IP stack
+ it is necessary to make definition of preprocessor symbol USE_LWIPSOCK
+ visible to libcurl and curl compilation processes. To set this definition
+ you have the following alternatives:
+
+ - Modify lib/config-win32.h and src/config-win32.h
+ - Modify lib/Makefile.vc6
+ - Add definition to Project/Settings/C/C++/General/Preprocessor Definitions
+ in the vc6libcurl.dsw/vc6libcurl.dsp Visual C++ 6 IDE project.
+
+ Once that libcurl has been built with BSD-style lwIP TCP/IP stack support,
+ in order to use it with your program it is mandatory that your program
+ includes lwIP header file <lwip/opt.h> (or another lwIP header that includes
+ this) before including any libcurl header. Your program does not need the
+ USE_LWIPSOCK preprocessor definition which is for libcurl internals only.
+
+ Compilation has been verified with lwIP 1.4.0 and contrib-1.4.0 from:
+
+ http://download.savannah.gnu.org/releases/lwip/lwip-1.4.0.zip
+ http://download.savannah.gnu.org/releases/lwip/contrib-1.4.0.zip
+
+ This BSD-style lwIP TCP/IP stack support must be considered experimental
+ given that it has been verified that lwIP 1.4.0 still needs some polish,
+ and libcurl might yet need some additional adjustment, caveat emptor.
+
+ Important static libcurl usage note
+ -----------------------------------
+
+ When building an application that uses the static libcurl library, you must
+ add '-DCURL_STATICLIB' to your CFLAGS. Otherwise the linker will look for
+ dynamic import symbols.
+
+
+Apple iOS and Mac OS X
+======================
+ On recent Apple operating systems, curl can be built to use Apple's
+ SSL/TLS implementation, Secure Transport, instead of OpenSSL. To build with
+ Secure Transport for SSL/TLS, use the configure option --with-darwinssl. (It
+ is not necessary to use the option --without-ssl.) This feature requires iOS
+ 5.0 or later, or OS X 10.5 ("Leopard") or later.
+
+ When Secure Transport is in use, the curl options --cacert and --capath and
+ their libcurl equivalents, will be ignored, because Secure Transport uses
+ the certificates stored in the Keychain to evaluate whether or not to trust
+ the server. This, of course, includes the root certificates that ship with
+ the OS. The --cert and --engine options, and their libcurl equivalents, are
+ currently unimplemented in curl with Secure Transport.
+
+ For OS X users: In OS X 10.8 ("Mountain Lion"), Apple made a major
+ overhaul to the Secure Transport API that, among other things, added
+ support for the newer TLS 1.1 and 1.2 protocols. To get curl to support
+ TLS 1.1 and 1.2, you must build curl on Mountain Lion or later, or by
+ using the equivalent SDK. If you set the MACOSX_DEPLOYMENT_TARGET
+ environmental variable to an earlier version of OS X prior to building curl,
+ then curl will use the new Secure Transport API on Mountain Lion and later,
+ and fall back on the older API when the same curl binary is executed on
+ older cats. For example, running these commands in curl's directory in the
+ shell will build the code such that it will run on cats as old as OS X 10.6
+ ("Snow Leopard") (using bash):
+
+ export MACOSX_DEPLOYMENT_TARGET="10.6"
+ ./configure --with-darwinssl
+ make
+
+
+IBM OS/2
+========
+ Building under OS/2 is not much different from building under unix.
+ You need:
+
+ - emx 0.9d
+ - GNU make
+ - GNU patch
+ - ksh
+ - GNU bison
+ - GNU file utilities
+ - GNU sed
+ - autoconf 2.13
+
+ If you want to build with OpenSSL or OpenLDAP support, you'll need to
+ download those libraries, too. Dirk Ohme has done some work to port SSL
+ libraries under OS/2, but it looks like he doesn't care about emx. You'll
+ find his patches on: http://come.to/Dirk_Ohme
+
+ If during the linking you get an error about _errno being an undefined
+ symbol referenced from the text segment, you need to add -D__ST_MT_ERRNO__
+ in your definitions.
+
+ If everything seems to work fine but there's no curl.exe, you need to add
+ -Zexe to your linker flags.
+
+ If you're getting huge binaries, probably your makefiles have the -g in
+ CFLAGS.
+
+
+VMS
+===
+ (The VMS section is in whole contributed by the friendly Nico Baggus)
+
+ Curl seems to work with FTP & HTTP other protocols are not tested. (the
+ perl http/ftp testing server supplied as testing too cannot work on VMS
+ because vms has no concept of fork(). [ I tried to give it a whack, but
+ that's of no use.
+
+ SSL stuff has not been ported.
+
+ Telnet has about the same issues as for Win32. When the changes for Win32
+ are clear maybe they'll work for VMS too. The basic problem is that select
+ ONLY works for sockets.
+
+ Marked instances of fopen/[f]stat that might become a problem, especially
+ for non stream files. In this regard, the files opened for writing will be
+ created stream/lf and will thus be safe. Just keep in mind that non-binary
+ read/wring from/to files will have a records size limit of 32767 bytes
+ imposed.
+
+ Stat to get the size of the files is again only safe for stream files &
+ fixed record files without implied CC.
+
+ -- My guess is that only allowing access to stream files is the quickest
+ way to get around the most issues. Therefore all files need to to be
+ checked to be sure they will be stream/lf before processing them. This is
+ the easiest way out, I know. The reason for this is that code that needs to
+ report the filesize will become a pain in the ass otherwise.
+
+ Exit status.... Well we needed something done here,
+
+ VMS has a structured exist status:
+ | 3 | 2 | 1 | 0|
+ |1098|765432109876|5432109876543|210|
+ +----+------------+-------------+---+
+ |Ctrl| Facility | Error code |sev|
+ +----+------------+-------------+---+
+
+ With the Ctrl-bits an application can tell if part or the whole message has
+ already been printed from the program, DCL doesn't need to print it again.
+
+ Facility - basically the program ID. A code assigned to the program
+ the name can be fetched from external or internal message libraries
+ Error code - the err codes assigned by the application
+ Sev. - severity: Even = error, off = non error
+ 0 = Warning
+ 1 = Success
+ 2 = Error
+ 3 = Information
+ 4 = Fatal
+ <5-7> reserved.
+
+ This all presents itself with:
+ %<FACILITY>-<Sev>-<Errorname>, <Error message>
+
+ See also the src/curlmsg.msg file, it has the source for the messages In
+ src/main.c a section is devoted to message status values, the globalvalues
+ create symbols with certain values, referenced from a compiled message
+ file. Have all exit function use a exit status derived from a translation
+ table with the compiled message codes.
+
+ This was all compiled with:
+
+ Compaq C V6.2-003 on OpenVMS Alpha V7.1-1H2
+
+ So far for porting notes as of:
+ 13-jul-2001
+ N. Baggus
+
+
+QNX
+===
+ (This section was graciously brought to us by David Bentham)
+
+ As QNX is targeted for resource constrained environments, the QNX headers
+ set conservative limits. This includes the FD_SETSIZE macro, set by default
+ to 32. Socket descriptors returned within the CURL library may exceed this,
+ resulting in memory faults/SIGSEGV crashes when passed into select(..)
+ calls using fd_set macros.
+
+ A good all-round solution to this is to override the default when building
+ libcurl, by overriding CFLAGS during configure, example
+ # configure CFLAGS='-DFD_SETSIZE=64 -g -O2'
+
+
+RISC OS
+=======
+ The library can be cross-compiled using gccsdk as follows:
+
+ CC=riscos-gcc AR=riscos-ar RANLIB='riscos-ar -s' ./configure \
+ --host=arm-riscos-aof --without-random --disable-shared
+ make
+
+ where riscos-gcc and riscos-ar are links to the gccsdk tools.
+ You can then link your program with curl/lib/.libs/libcurl.a
+
+
+AmigaOS
+=======
+ (This section was graciously brought to us by Diego Casorran)
+
+ To build cURL/libcurl on AmigaOS just type 'make amiga' ...
+
+ What you need is: (not tested with others versions)
+
+ GeekGadgets / gcc 2.95.3 (http://www.geekgadgets.org/)
+
+ AmiTCP SDK v4.3 (http://www.aminet.net/comm/tcp/AmiTCP-SDK-4.3.lha)
+
+ Native Developer Kit (http://www.amiga.com/3.9/download/NDK3.9.lha)
+
+ As no ixemul.library is required you will be able to build it for
+ WarpOS/PowerPC (not tested by me), as well a MorphOS version should be
+ possible with no problems.
+
+ To enable SSL support, you need a OpenSSL native version (without ixemul),
+ you can find a precompiled package at http://amiga.sourceforge.net/OpenSSL/
+
+
+NetWare
+=======
+ To compile curl.nlm / libcurl.nlm you need:
+ - either any gcc / nlmconv, or CodeWarrior 7 PDK 4 or later.
+ - gnu make and awk running on the platform you compile on;
+ native Win32 versions can be downloaded from:
+ http://www.gknw.net/development/prgtools/
+ - recent Novell LibC SDK available from:
+ http://developer.novell.com/ndk/libc.htm
+ - or recent Novell CLib SDK available from:
+ http://developer.novell.com/ndk/clib.htm
+ - optional recent Novell CLDAP SDK available from:
+ http://developer.novell.com/ndk/cldap.htm
+ - optional zlib sources (static or dynamic linking with zlib.imp);
+ sources with NetWare Makefile can be obtained from:
+ http://www.gknw.net/mirror/zlib/
+ - optional OpenSSL sources (version 0.9.8 or later build with BSD sockets);
+ you can find precompiled packages at:
+ http://www.gknw.net/development/ossl/netware/
+ for CLIB-based builds OpenSSL 0.9.8h or later is required - earlier versions
+ don't support building with CLIB BSD sockets.
+ - optional SSH2 sources (version 0.17 or later);
+
+ Set a search path to your compiler, linker and tools; on Linux make
+ sure that the var OSTYPE contains the string 'linux'; set the var
+ NDKBASE to point to the base of your Novell NDK; and then type
+ 'make netware' from the top source directory; other targets available
+ are 'netware-ssl', 'netware-ssl-zlib', 'netware-zlib' and 'netware-ares';
+ if you need other combinations you can control the build with the
+ environment variables WITH_SSL, WITH_ZLIB, WITH_ARES, WITH_SSH2, and
+ ENABLE_IPV6; you can set LINK_STATIC=1 to link curl.nlm statically.
+ By default LDAP support is enabled, however currently you will need a patch
+ in order to use the CLDAP NDK with BSD sockets (Novell Bug 300237):
+ http://www.gknw.net/test/curl/cldap_ndk/ldap_ndk.diff
+ I found on some Linux systems (RH9) that OS detection didn't work although
+ a 'set | grep OSTYPE' shows the var present and set; I simply overwrote it
+ with 'OSTYPE=linux-rh9-gnu' and the detection in the Makefile worked...
+ Any help in testing appreciated!
+ Builds automatically created 8 times a day from current git are here:
+ http://www.gknw.net/mirror/curl/autobuilds/
+ the status of these builds can be viewed at the autobuild table:
+ http://curl.haxx.se/dev/builds.html
+
+
+eCos
+====
+ curl does not use the eCos build system, so you must first build eCos
+ separately, then link curl to the resulting eCos library. Here's a sample
+ configure line to do so on an x86 Linux box targeting x86:
+
+ GCCLIB=`gcc -print-libgcc-file-name` && \
+ CFLAGS="-D__ECOS=1 -nostdinc -I$ECOS_INSTALL/include \
+ -I`dirname $GCCLIB`/include" \
+ LDFLAGS="-nostdlib -Wl,--gc-sections -Wl,-static \
+ -L$ECOS_INSTALL/lib -Ttarget.ld -ltarget" \
+ ./configure --host=i386 --disable-shared \
+ --without-ssl --without-zlib --disable-manual --disable-ldap
+
+ In most cases, eCos users will be using libcurl from within a custom
+ embedded application. Using the standard 'curl' executable from
+ within eCos means facing the limitation of the standard eCos C
+ startup code which does not allow passing arguments in main(). To
+ run 'curl' from eCos and have it do something useful, you will need
+ to either modify the eCos startup code to pass in some arguments, or
+ modify the curl application itself to retrieve its arguments from
+ some location set by the bootloader or hard-code them.
+
+ Something like the following patch could be used to hard-code some
+ arguments. The MTAB_ENTRY line mounts a RAM disk as the root filesystem
+ (without mounting some kind of filesystem, eCos errors out all file
+ operations which curl does not take to well). The next section synthesizes
+ some command-line arguments for curl to use, in this case to direct curl
+ to read further arguments from a file. It then creates that file on the
+ RAM disk and places within it a URL to download: a file: URL that
+ just happens to point to the configuration file itself. The results
+ of running curl in this way is the contents of the configuration file
+ printed to the console.
+
+--- src/main.c 19 Jul 2006 19:09:56 -0000 1.363
++++ src/main.c 24 Jul 2006 21:37:23 -0000
+@@ -4286,11 +4286,31 @@
+ }
+
+
++#ifdef __ECOS
++#include <cyg/fileio/fileio.h>
++MTAB_ENTRY( testfs_mte1,
++ "/",
++ "ramfs",
++ "",
++ 0);
++#endif
+
+ int main(int argc, char *argv[])
+ {
+ int res;
+ struct Configurable config;
++#ifdef __ECOS
++ char *args[] = {"ecos-curl", "-K", "curlconf.txt"};
++ FILE *f;
++ argc = sizeof(args)/sizeof(args[0]);
++ argv = args;
++
++ f = fopen("curlconf.txt", "w");
++ if (f) {
++ fprintf(f, "--url file:curlconf.txt");
++ fclose(f);
++ }
++#endif
+ memset(&config, 0, sizeof(struct Configurable));
+
+ config.errors = stderr; /* default errors to stderr */
+
+
+Minix
+=====
+ curl can be compiled on Minix 3 using gcc or ACK (starting with
+ ver. 3.1.3). Ensure that GNU gawk and bash are both installed and
+ available in the PATH.
+
+ ACK
+ ---
+ Increase the heap sizes of the compiler with the command:
+
+ binsizes xxl
+
+ then configure and compile curl with:
+
+ ./configure CC=cc LD=cc AR=/usr/bin/aal GREP=grep \
+ CPPFLAGS='-D_POSIX_SOURCE=1 -I/usr/local/include'
+ make
+ chmem =256000 src/curl
+
+ GCC
+ ---
+ Make sure gcc is in your PATH with the command:
+
+ export PATH=/usr/gnu/bin:$PATH
+
+ then configure and compile curl with:
+
+ ./configure CC=gcc AR=/usr/gnu/bin/gar GREP=grep
+ make
+ chmem =256000 src/curl
+
+
+Symbian OS
+==========
+ The Symbian OS port uses the Symbian build system to compile. From the
+ packages/Symbian/group/ directory, run:
+
+ bldmake bldfiles
+ abld build
+
+ to compile and install curl and libcurl using SBSv1. If your Symbian
+ SDK doesn't include support for P.I.P.S., you will need to contact
+ your SDK vendor to obtain that first.
+
+
+VxWorks
+========
+ Build for VxWorks is performed using cross compilation.
+ That means you build on Windows machine using VxWorks tools and
+ run the built image on the VxWorks device.
+
+ To build libcurl for VxWorks you need:
+
+ - CYGWIN (free, http://cygwin.com/)
+ - Wind River Workbench (commercial)
+
+ If you have CYGWIN and Workbench installed on you machine
+ follow after next steps:
+
+ 1. Open the Command Prompt window and change directory ('cd')
+ to the libcurl 'lib' folder.
+ 2. Add CYGWIN 'bin' folder to the PATH environment variable.
+ For example, type 'set PATH=C:/embedded/cygwin/bin;%PATH%'.
+ 3. Adjust environment variables defined in 'Environment' section
+ of the Makefile.vxworks file to point to your software folders.
+ 4. Build the libcurl by typing 'make -f ./Makefile.vxworks'
+
+ As a result the libcurl.a library should be created in the 'lib' folder.
+ To clean the build results type 'make -f ./Makefile.vxworks clean'.
+
+
+Android
+=======
+ Method using the static makefile:
+ - see the build notes in the packages/Android/Android.mk file.
+
+ Method using a configure cross-compile (tested with Android NDK r7c, r8):
+ - prepare the toolchain of the Android NDK for standalone use; this can
+ be done by invoking the script:
+ ./build/tools/make-standalone-toolchain.sh
+ which creates a usual cross-compile toolchain. Lets assume that you put
+ this toolchain below /opt then invoke configure with something like:
+ export PATH=/opt/arm-linux-androideabi-4.4.3/bin:$PATH
+ ./configure --host=arm-linux-androideabi [more configure options]
+ make
+ - if you want to compile directly from our GIT repo you might run into
+ this issue with older automake stuff:
+ checking host system type...
+ Invalid configuration `arm-linux-androideabi':
+ system `androideabi' not recognized
+ configure: error: /bin/sh ./config.sub arm-linux-androideabi failed
+ this issue can be fixed with using more recent versions of config.sub
+ and config.guess which can be obtained here:
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=tree
+ you need to replace your system-own versions which usually can be
+ found in your automake folder:
+ find /usr -name config.sub
+
+ Wrapper for pkg-config
+ - In order to make proper use of pkg-config so that configure is able to
+ find all dependencies you should create a wrapper script for pkg-config;
+ file /opt/arm-linux-androideabi-4.4.3/bin/arm-linux-androideabi-pkg-config:
+
+ #!/bin/sh
+ SYSROOT=$(dirname ${0%/*})/sysroot
+ export PKG_CONFIG_DIR=
+ export PKG_CONFIG_LIBDIR=${SYSROOT}/usr/local/lib/pkgconfig:${SYSROOT}/usr/share/pkgconfig
+ export PKG_CONFIG_SYSROOT_DIR=${SYSROOT}
+ exec pkg-config "$@"
+
+ also create a copy or symlink with name arm-unknown-linux-androideabi-pkg-config.
+
+
+CROSS COMPILE
+=============
+ (This section was graciously brought to us by Jim Duey, with additions by
+ Dan Fandrich)
+
+ Download and unpack the cURL package.
+
+ 'cd' to the new directory. (e.g. cd curl-7.12.3)
+
+ Set environment variables to point to the cross-compile toolchain and call
+ configure with any options you need. Be sure and specify the '--host' and
+ '--build' parameters at configuration time. The following script is an
+ example of cross-compiling for the IBM 405GP PowerPC processor using the
+ toolchain from MonteVista for Hardhat Linux.
+
+ (begin script)
+
+ #! /bin/sh
+
+ export PATH=$PATH:/opt/hardhat/devkit/ppc/405/bin
+ export CPPFLAGS="-I/opt/hardhat/devkit/ppc/405/target/usr/include"
+ export AR=ppc_405-ar
+ export AS=ppc_405-as
+ export LD=ppc_405-ld
+ export RANLIB=ppc_405-ranlib
+ export CC=ppc_405-gcc
+ export NM=ppc_405-nm
+
+ ./configure --target=powerpc-hardhat-linux \
+ --host=powerpc-hardhat-linux \
+ --build=i586-pc-linux-gnu \
+ --prefix=/opt/hardhat/devkit/ppc/405/target/usr/local \
+ --exec-prefix=/usr/local
+
+ (end script)
+
+ You may also need to provide a parameter like '--with-random=/dev/urandom'
+ to configure as it cannot detect the presence of a random number
+ generating device for a target system. The '--prefix' parameter
+ specifies where cURL will be installed. If 'configure' completes
+ successfully, do 'make' and 'make install' as usual.
+
+ In some cases, you may be able to simplify the above commands to as
+ little as:
+
+ ./configure --host=ARCH-OS
+
+
+REDUCING SIZE
+=============
+ There are a number of configure options that can be used to reduce the
+ size of libcurl for embedded applications where binary size is an
+ important factor. First, be sure to set the CFLAGS variable when
+ configuring with any relevant compiler optimization flags to reduce the
+ size of the binary. For gcc, this would mean at minimum the -Os option,
+ and potentially the -march=X and -mdynamic-no-pic options as well, e.g.
+
+ ./configure CFLAGS='-Os' ...
+
+ Note that newer compilers often produce smaller code than older versions
+ due to improved optimization.
+
+ Be sure to specify as many --disable- and --without- flags on the configure
+ command-line as you can to disable all the libcurl features that you
+ know your application is not going to need. Besides specifying the
+ --disable-PROTOCOL flags for all the types of URLs your application
+ will not use, here are some other flags that can reduce the size of the
+ library:
+
+ --disable-ares (disables support for the C-ARES DNS library)
+ --disable-cookies (disables support for HTTP cookies)
+ --disable-crypto-auth (disables HTTP cryptographic authentication)
+ --disable-ipv6 (disables support for IPv6)
+ --disable-manual (disables support for the built-in documentation)
+ --disable-proxy (disables support for HTTP and SOCKS proxies)
+ --disable-verbose (eliminates debugging strings and error code strings)
+ --enable-hidden-symbols (eliminates unneeded symbols in the shared library)
+ --without-libidn (disables support for the libidn DNS library)
+ --without-ssl (disables support for SSL/TLS)
+ --without-zlib (disables support for on-the-fly decompression)
+
+ The GNU compiler and linker have a number of options that can reduce the
+ size of the libcurl dynamic libraries on some platforms even further.
+ Specify them by providing appropriate CFLAGS and LDFLAGS variables on the
+ configure command-line, e.g.
+ CFLAGS="-Os -ffunction-sections -fdata-sections \
+ -fno-unwind-tables -fno-asynchronous-unwind-tables" \
+ LDFLAGS="-Wl,-s -Wl,-Bsymbolic -Wl,--gc-sections"
+
+ Be sure also to strip debugging symbols from your binaries after
+ compiling using 'strip' (or the appropriate variant if cross-compiling).
+ If space is really tight, you may be able to remove some unneeded
+ sections of the shared library using the -R option to objcopy (e.g. the
+ .comment section).
+
+ Using these techniques it is possible to create a basic HTTP-only shared
+ libcurl library for i386 Linux platforms that is only 106 KiB in size, and
+ an FTP-only library that is 108 KiB in size (as of libcurl version 7.27.0,
+ using gcc 4.6.3).
+
+ You may find that statically linking libcurl to your application will
+ result in a lower total size than dynamically linking.
+
+ Note that the curl test harness can detect the use of some, but not all, of
+ the --disable statements suggested above. Use will cause tests relying on
+ those features to fail. The test harness can be manually forced to skip
+ the relevant tests by specifying certain key words on the runtests.pl
+ command line. Following is a list of appropriate key words:
+
+ --disable-cookies !cookies
+ --disable-crypto-auth !HTTP\ Digest\ auth !HTTP\ proxy\ Digest\ auth
+ --disable-manual !--manual
+ --disable-proxy !HTTP\ proxy !proxytunnel !SOCKS4 !SOCKS5
+
+
+PORTS
+=====
+ This is a probably incomplete list of known hardware and operating systems
+ that curl has been compiled for. If you know a system curl compiles and
+ runs on, that isn't listed, please let us know!
+
+ - Alpha DEC OSF 4
+ - Alpha Digital UNIX v3.2
+ - Alpha FreeBSD 4.1, 4.5
+ - Alpha Linux 2.2, 2.4
+ - Alpha NetBSD 1.5.2
+ - Alpha OpenBSD 3.0
+ - Alpha OpenVMS V7.1-1H2
+ - Alpha Tru64 v5.0 5.1
+ - AVR32 Linux
+ - ARM Android 1.5, 2.1, 2.3, 3.2, 4.x
+ - ARM INTEGRITY
+ - ARM iOS
+ - Cell Linux
+ - Cell Cell OS
+ - HP-PA HP-UX 9.X 10.X 11.X
+ - HP-PA Linux
+ - HP3000 MPE/iX
+ - MicroBlaze uClinux
+ - MIPS IRIX 6.2, 6.5
+ - MIPS Linux
+ - OS/400
+ - Pocket PC/Win CE 3.0
+ - Power AIX 3.2.5, 4.2, 4.3.1, 4.3.2, 5.1, 5.2
+ - PowerPC Darwin 1.0
+ - PowerPC INTEGRITY
+ - PowerPC Linux
+ - PowerPC Mac OS 9
+ - PowerPC Mac OS X
+ - SH4 Linux 2.6.X
+ - SH4 OS21
+ - SINIX-Z v5
+ - Sparc Linux
+ - Sparc Solaris 2.4, 2.5, 2.5.1, 2.6, 7, 8, 9, 10
+ - Sparc SunOS 4.1.X
+ - StrongARM (and other ARM) RISC OS 3.1, 4.02
+ - StrongARM/ARM7/ARM9 Linux 2.4, 2.6
+ - StrongARM NetBSD 1.4.1
+ - Symbian OS (P.I.P.S.) 9.x
+ - TPF
+ - Ultrix 4.3a
+ - UNICOS 9.0
+ - i386 BeOS
+ - i386 DOS
+ - i386 eCos 1.3.1
+ - i386 Esix 4.1
+ - i386 FreeBSD
+ - i386 HURD
+ - i386 Haiku OS
+ - i386 Linux 1.3, 2.0, 2.2, 2.3, 2.4, 2.6
+ - i386 Mac OS X
+ - i386 MINIX 3.1
+ - i386 NetBSD
+ - i386 Novell NetWare
+ - i386 OS/2
+ - i386 OpenBSD
+ - i386 QNX 6
+ - i386 SCO unix
+ - i386 Solaris 2.7
+ - i386 Windows 95, 98, ME, NT, 2000, XP, 2003
+ - i486 ncr-sysv4.3.03 (NCR MP-RAS)
+ - ia64 Linux 2.3.99
+ - m68k AmigaOS 3
+ - m68k Linux
+ - m68k uClinux
+ - m68k OpenBSD
+ - m88k dg-dgux5.4R3.00
+ - s390 Linux
+ - x86_64 Linux
+ - XScale/PXA250 Linux 2.4
+ - Nios II uClinux
+
+Useful URLs
+===========
+
+axTLS http://axtls.sourceforge.net/
+c-ares http://c-ares.haxx.se/
+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/
+OpenLDAP http://www.openldap.org/
+OpenSSL http://www.openssl.org/
+PolarSSL http://polarssl.org/
+yassl http://www.yassl.com/
+Zlib http://www.zlib.net/
+
+MingW http://www.mingw.org/
+MinGW-w64 http://mingw-w64.sourceforge.net/
+OpenWatcom http://www.openwatcom.org/
diff --git a/libs/libcurl/docs/INSTALL.devcpp b/libs/libcurl/docs/INSTALL.devcpp
new file mode 100644
index 0000000000..46d1836af9
--- /dev/null
+++ b/libs/libcurl/docs/INSTALL.devcpp
@@ -0,0 +1,302 @@
+DevCpp-Mingw Install & Compilation Sept 2005
+==================================
+
+Reference Emails available at curl@haxx.se:
+
+ Libcurl Install and Use Issues
+ Awaiting an Answer for Win 32 Install
+ res = curl_easy_perform(curl); Error
+ Makefile Issues
+
+
+Having previously done a thorough review of what was available that met my
+requirements under GPL, I settled for Libcurl as the software of choice for
+many reasons not the least of which was the support.
+
+Background
+----------
+
+This quest started when I innocently tried to incorporate the libcurl library
+into my simple source code. I figured that a few easy steps would accomplish
+this without major headaches. I had no idea that I would be facing an almost
+insurmountable challenge.
+
+The main problem lies in two areas. First the bulk of support for libcurl
+exists for a Unix/linux command line environments. This is of little help when
+it comes to Windows O/S.
+
+Secondly the help that does exist for the Windows O/S focused around mingw
+through a command line argument environment.
+
+You may ask "Why is this a problem?"
+
+I'm using a Windows O/S with DevCpp. For those of you who are unfamiliar with
+DevCpp, it is a window shell GUI that replaces the command line environment
+for gcc. A definite improvement that I am unwilling to give up. However using
+DevCpp presented its own set of issues. Inadvertently I also made some
+careless errors such as compiling the 7.14 version of Makefile with an older
+version of source code. Thanks to Dan Fandrich for picking this up.
+
+I did eventually with the help of Daniel, Phillipe and others manage to
+implement successfully (the only mingw available version)
+curl-7.13.0-win32-ssl-devel-mingw32 into the DevCpp environment. Only the
+dynamic libcurl.dll libcurldll.a libraries worked. The static library which I
+was interested in did not. Furthermore when I tried to implement one of the
+examples included with the curl package (get info.c) it caused the executable
+to crash. Tracing the bug I found it in the code and function res =
+curl_easy_perform(curl);.
+
+At this point I had to make a choice as to whether invest my limited
+time-energy resource to fixing the bug or to compile the new version
+available. After searching the archives I found a very similar or the same bug
+reported from version 7.12x on. Daniel did inform me that he thought that this
+bug had been fixed with the latest version. So I proceeded to compile the
+latest SSL version where I faced other challenges.
+
+In order to make this process unremarkable for others using the same
+environment I decided to document the process so that others will find it
+routine. It would be a shame if newbies could not implement this excellent
+package for their use.
+
+I would like to thank the many others in this forum and in the DevCpp forum
+for their help. Without your help I may either have given up or it would have
+taken me many times longer to achieve success.
+
+The Cookbook Approach
+---------------------
+
+This discussion will be confined to a SSL static library compilation and
+installation. Limited mention and comments will be inserted where appropriate
+to help with non-SSL, dynamic libraries and executables.
+
+
+ Using Makefile from DevCpp to compile Libcurl libraries
+
+Preamble
+--------
+
+Using the latest version release - curl-7.14.0.tar.gz. Curl source code is
+platform independent. This simply means that the source code can be compiled
+for any Operating System (Linux/Unix Windows etc. and variations of thereof).
+
+The first thing to note is that inside curl-7.14.0 you will find two folders
+lib and src. Both contain Makefile.m32 (required for win mingw library or exe
+compilation) files which are different. The main difference between these two
+folders and the makefiles is that the src folder contents are used to compile
+an executable file(curl.exe) while the lib folder contents are used to compile
+a static (libcurl.a) and dynamic (libcurl.dll & libcurldll.a) file that can be
+used to compile libcurl with your own source code so that one can use and
+access all libcurl functions.
+
+Before we start please make sure that DevCpp is installed properly. In
+particular make sure you have no spaces in the name of any of the directories
+and subdirectories where DevCpp is installed. Failure to comply with the
+install instructions may produce erratic behaviour in DevCpp. For further info
+check the following sites
+
+http://aditsu.freeunixhost.com/dev-cpp-faq.html
+http://sourceforge.net/forum/message.php?msg_id=3252213
+
+As I have mentioned before I will confine this to the SSL Library compilations
+but the process is very similar for compilation of the executable - curl.exe;
+just substitute the src folder makefile in its stead.
+
+First use a text processor Notepad, or your own favourite text processor. To
+engage your favourite text processor, select Makefile.m32 click once with your
+mouse on file icon; icon turns blue, press the shift key and right-click on
+mouse, menu appears select "Open with", select your favourite text processor.
+
+Next read the contents of Makefile.m32. It includes instructions on its use.
+
+Method I - DOS Command Line
+---------------------------
+
+Note - The only reason I have included this method is that Method II which is
+the preferred method for compiling does not allow for the setting of option
+switches (e.g. SSL = 1 or SSL =0). At least that's what they tell me at the
+Dev-Cpp forum.
+
+1 - Make a copy of (D:\Dev-Cpp\bin) bin folder and name it "bin Original"
+place it in the Dev-Cpp installed directory (D:\Dev-Cpp\ for this example)
+
+2 - Copy the entire contents of the LIB folder of curl-7.14.0.tar.gz or zip
+version into the bin folder above (D:\Dev-Cpp\bin). The reason being is that
+the make.exe file resides in this folder. Make.exe will use - Makefile.m32,
+Makefile.inc, and the source code included in the lib folder to compile the
+source code. There is a PATH issue with make.exe that remains unresolved at
+least for me. Unless the entire source code to be compiled is placed entirely
+within the directory of make.exe an error message will be generated - "file
+xxxx.yyy not available".
+
+3- Go to Dev-Cpp\bin and double click on make .exe. You will see a DOS window
+quickly pop up and close very quickly. Not to worry! Please do not skip this
+step.
+
+4- Click on the start button\Programs\MS-DOS Prompt.Once the DOS Window is up
+Type the disk drive letter (e.g. E: ) engage the enter button. The path should
+automatically take you to the directory of the make.exe file.
+
+5- To compile the source code simply type at the DOS prompt make -f
+Makefile.m32 as per instructions contained in the Makefile.m32 file (use any
+text processor to read instructions). I don't believe that this makefile
+allows for the option of non SSL. Ignore any warnings.
+
+6- Collect and make copies of libcurl.a, libcurl.dll, libcurldll.a and any *.o
+compilations you might need in another directory outside of the bin directory
+as you will need this files shortly to set up libcurl for use with
+Dev-cpp. For most apps *.o is not required. Later on we will show what to do
+with these files.
+
+7- You are finished but before closing we need to do cleanup - erase the bin
+folder and rename the "bin Original" folder created in step 1 to bin.
+
+Note to compile a curl executable the process is probably similar but instead
+of using the LIB folder contents use the SRC folder contents and Makefiles in
+curl-7.14.0.tar.gz. File directories relative placements must be respected for
+compiling to take place successfully. This may not be possible with the PATH
+problem that make.exe experiences. If anyone has solved this PATH issue and
+please make sure it actually works on Win 9x/2000/XP before letting me
+know. Then please let me or Daniel in on the solution so that it can be
+included with these instructions. Thanks.
+
+or
+
+Method II - Dev-Cpp GUI
+-----------------------
+
+1- Copy the entire contents of the LIB folder of curl-7.14.0.tar.gz or zip
+version into any folder outside of (Dev-Cpp\bin).
+
+2- Drop the File/New/click on Project.
+
+3- New Project Dialogue box appears. Double click on the Static Library.
+
+4- Create Project Dialogue box appears. Select the LIB folder location to
+place and locate your Project File Name. Placing the Project File Name
+elsewhere may cause problems (PATH issue problem again).
+
+5- Drop down the Project/Project Options. Project Options Dialogue box
+appears.
+
+6- Select the Makefile tab in the Project Options Dialogue Box. Check Box -
+Use Custom Makefile. Click on the Folder icon at the extreme right of the
+Check Box. Select Makefile.m32 in the folder wherever you have placed the
+contents of the LIB Folder. Press OK and close the Dialogue Box.
+
+7- Drop the Menu Project/Click on Add to Project. Open File Dialogue Box
+appears. The Dialogue Box should open in the folder wherever you have placed
+the contents of the LIB Folder. If not go there.
+
+8- Select Crtl-A to select all files in the LIB folder. Click on open to add
+files and close box. Wait till all files are added. This may take 30 seconds
+or longer.
+
+9- Drop the Menu Execute/Click on Compile.
+
+10- That's it.
+
+
+ The following steps must be completed if Curl is to work properly
+ =================================================================
+
+LIB folder inclusions (*.a placement)
+-------------------------------------
+
+1- Refer to Method I - DOS Command Line point # 6 Take libcurl.a, libcurldll.a
+and install it in the directory C( or whichever drive Dev is installed)
+:\Dev-Cpp\lib.
+
+
+Include Folder
+--------------
+
+1- Create a new folder by the name of curl (do not change the name curl to
+some other name as it will cause major issues) in the directory
+C:\Dev-Cpp\include.
+
+2- Copy the entire contents of the curl folder of curl-7.14.0.tar.gz or zip
+ version into the newly created curl directory - C:\Dev-Cpp\include\curl.
+
+Links To Include And Lib Folder
+-------------------------------
+
+1- Drop the Menu - Tools\Compiler Options\Directories\Libraries. Make sure
+that C( or whichever drive Dev is installed):\DEV-CPP\lib is included.
+
+2- Next select the Menu - Tools\Compiler Options\Directories\C Includes. Make
+sure that C:\DEV-CPP\include and C:\Dev-Cpp\include\curl are included.
+
+3- Next select the Menu - Tools\Compiler Options\Directories\C++
+Includes. Make sure that C:\DEV-CPP\include and C:\Dev-Cpp\include\curl are
+included.
+
+Linker Links
+------------
+
+1- Drop the Menu - Tools\Compiler Options\Directories\Compiler.
+
+2- Make sure that the box "Add these commands to the linker command line" is
+checked.
+
+3- Include in the white space immediately below the box referred in 2 -lcurl
+-lws2_32.
+
+SSL Files
+---------
+
+1- Get the latest openSSL (as of time of this writing)
+openssl-0.9.7e-win32-bin.zip for the minimalist package of the openssl-0.9.7e
+binaries ported to MS Windows 95/98/NT/XP using the MingW32/GCC-3.1
+development environment. The file may be downloaded at
+http://curl.haxx.se/download/.
+
+2- Open the above zip file. You will find two files - SDL.dll,
+SDL_mixer.dll. Install them in the directory C:\WINDOWS\SYSTEM32 for Win 9x
+users and c:\winnt\system32 for NT-family users.
+
+Multithreading Files
+--------------------
+
+To be completed
+
+#define
+-------
+
+1- Make sure that your program includes the following - #define CURL_STATICLIB
+must be declared FIRST before any other define functions may be
+added. Otherwise you may experience link errors.
+
+2- Don't forget to include #include "curl/curl.h".
+
+e.g.
+ #define CURL_STATICLIB
+#include <windows.h>
+ #include "curl/curl.h"
+#include <fstream>
+#include <iostream>
+#include <vector>
+etc...
+
+
+Static or Dynamic Library
+-------------------------
+
+The above steps apply for the use by a static library. Should you choose to
+use a dynamic library you will be required to perform these additional steps.
+
+1- Refer to Method I - DOS Command Line point # 6. Install libcurl.dll in the
+directory C:\WINDOWS\SYSTEM32 for Win 9x users and c:\winnt\system32 for
+NT-family users.
+
+2- Refer to Linker Links point 3 - Replace -lcurl with -lcurldll.
+
+Voila you're done.
+
+The non-SSL static Library build may not be possible to use at least as of the
+time of this writing - v7.14. Check reference emails - Phillipe and I found it
+impossible to fully compile as certain files were missing for linking. No big
+loss as SSL is a major plus.
+
+Hope this Helps
+
+Tom
diff --git a/libs/libcurl/docs/INTERNALS b/libs/libcurl/docs/INTERNALS
new file mode 100644
index 0000000000..66e11a46b7
--- /dev/null
+++ b/libs/libcurl/docs/INTERNALS
@@ -0,0 +1,471 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+INTERNALS
+
+ The project is split in two. The library and the client. The client part uses
+ the library, but the library is designed to allow other applications to use
+ it.
+
+ The largest amount of code and complexity is in the library part.
+
+GIT
+===
+ All changes to the sources are committed to the git repository as soon as
+ they're somewhat verified to work. Changes shall be committed as independently
+ as possible so that individual changes can be easier spotted and tracked
+ afterwards.
+
+ Tagging shall be used extensively, and by the time we release new archives we
+ should tag the sources with a name similar to the released version number.
+
+Portability
+===========
+
+ We write curl and libcurl to compile with C89 compilers. On 32bit and up
+ machines. Most of libcurl assumes more or less POSIX compliance but that's
+ not a requirement.
+
+ We write libcurl to build and work with lots of third party tools, and we
+ want it to remain functional and buildable with these and later versions
+ (older versions may still work but is not what we work hard to maintain):
+
+ OpenSSL 0.9.6
+ GnuTLS 1.2
+ zlib 1.1.4
+ libssh2 0.16
+ c-ares 1.6.0
+ libidn 0.4.1
+ cyassl 2.0.0
+ openldap 2.0
+ MIT krb5 lib 1.2.4
+ qsossl V5R3M0
+ NSS 3.12.x
+ axTLS 1.2.7
+ Heimdal ?
+
+ On systems where configure runs, we aim at working on them all - if they have
+ a suitable C compiler. On systems that don't run configure, we strive to keep
+ curl running fine on:
+
+ Windows 98
+ AS/400 V5R3M0
+ Symbian 9.1
+ Windows CE ?
+ TPF ?
+
+ When writing code (mostly for generating stuff included in release tarballs)
+ we use a few "build tools" and we make sure that we remain functional with
+ these versions:
+
+ GNU Libtool 1.4.2
+ GNU Autoconf 2.57
+ GNU Automake 1.7 (we currently avoid 1.10 due to Solaris-related bugs)
+ GNU M4 1.4
+ perl 5.004
+ roffit 0.5
+ groff ? (any version that supports "groff -Tps -man [in] [out]")
+ ps2pdf (gs) ?
+
+Windows vs Unix
+===============
+
+ There are a few differences in how to program curl the unix way compared to
+ the Windows way. The four perhaps most notable details are:
+
+ 1. Different function names for socket operations.
+
+ In curl, this is solved with defines and macros, so that the source looks
+ the same at all places except for the header file that defines them. The
+ macros in use are sclose(), sread() and swrite().
+
+ 2. Windows requires a couple of init calls for the socket stuff.
+
+ That's taken care of by the curl_global_init() call, but if other libs also
+ do it etc there might be reasons for applications to alter that behaviour.
+
+ 3. The file descriptors for network communication and file operations are
+ not easily interchangeable as in unix.
+
+ We avoid this by not trying any funny tricks on file descriptors.
+
+ 4. When writing data to stdout, Windows makes end-of-lines the DOS way, thus
+ destroying binary data, although you do want that conversion if it is
+ text coming through... (sigh)
+
+ We set stdout to binary under windows
+
+ Inside the source code, We make an effort to avoid '#ifdef [Your OS]'. All
+ conditionals that deal with features *should* instead be in the format
+ '#ifdef HAVE_THAT_WEIRD_FUNCTION'. Since Windows can't run configure scripts,
+ we maintain a curl_config-win32.h file in lib directory that is supposed to
+ look exactly as a curl_config.h file would have looked like on a Windows
+ machine!
+
+ Generally speaking: always remember that this will be compiled on dozens of
+ operating systems. Don't walk on the edge.
+
+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
+ put in the lib/easy.c file.
+
+ curl_global_init_() and curl_global_cleanup() should be called by the
+ application to initialize and clean up global stuff in the library. As of
+ today, it can handle the global SSL initing if SSL is enabled and it can init
+ the socket layer on windows machines. libcurl itself has no "global" scope.
+
+ All printf()-style functions use the supplied clones in lib/mprintf.c. This
+ makes sure we stay absolutely platform independent.
+
+ curl_easy_init() allocates an internal struct and makes some initializations.
+ The returned handle does not reveal internals. This is the 'SessionHandle'
+ struct which works as an "anchor" struct for all curl_easy functions. All
+ connections performed will get connect-specific data allocated that should be
+ used for things related to particular connections/requests.
+
+ curl_easy_setopt() takes three arguments, where the option stuff must be
+ passed in pairs: the parameter-ID and the parameter-value. The list of
+ options is documented in the man page. This function mainly sets things in
+ the 'SessionHandle' struct.
+
+ 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.
+
+ 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
+ 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).
+
+ When Curl_connect is done, we are connected to the remote site. Then it is
+ time to tell the server to get a document/file. Curl_do() arranges this.
+
+ This function makes sure there's an allocated and initiated 'connectdata'
+ struct that is used for this particular connection only (although there may
+ be several requests performed on the same connect). A bunch of things are
+ inited/inherited from the SessionHandle struct.
+
+ o Curl_do()
+
+ Curl_do() makes sure the proper protocol-specific function is called. The
+ 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
+ lib/sendf.c) function to send printf-style formatted data to the remote
+ host and when they're ready to make the actual file transfer they call the
+ Curl_Transfer() function (in lib/transfer.c) to setup the transfer and
+ returns.
+
+ If this DO function fails and the connection is being re-used, libcurl will
+ then close this connection, setup a new connection and re-issue the DO
+ request on that. This is because there is no way to be perfectly sure that
+ we have discovered a dead connection before the DO function and thus we
+ might wrongly be re-using a connection that was closed by the remote peer.
+
+ Some time during the DO function, the Curl_setup_transfer() function must
+ 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 Curl_readwrite()
+
+ 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
+ called). The speedcheck functions in lib/speedcheck.c are also used to
+ verify that the transfer is as fast as required.
+
+ o Curl_done()
+
+ Called after a transfer is done. This function takes care of everything
+ that has to be done after a transfer. This function attempts to leave
+ matters in a state so that Curl_do() should be possible to call again on
+ the same connection (in a persistent connection case). It might also soon
+ be closed with Curl_disconnect().
+
+ o Curl_disconnect()
+
+ When doing normal connections and transfers, no one ever tries to close any
+ connections so this is not normally called when curl_easy_perform() is
+ 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.
+
+ This function cleans up all resources that are associated with a single
+ connection.
+
+
+ HTTP(S)
+
+ HTTP offers a lot and is the protocol in curl that uses the most lines of
+ code. There is a special file (lib/formdata.c) that offers all the multipart
+ post functions.
+
+ base64-functions for user+password stuff (and more) is in (lib/base64.c) and
+ all functions for parsing and sending cookies are found in (lib/cookie.c).
+
+ HTTPS uses in almost every means the same procedure as HTTP, with only two
+ exceptions: the connect procedure is different and the function used to read
+ or write from the socket is different, although the latter fact is hidden in
+ the source by the use of Curl_read() for reading and Curl_write() for writing
+ data to the remote server.
+
+ http_chunks.c contains functions that understands HTTP 1.1 chunked transfer
+ encoding.
+
+ An interesting detail with the HTTP(S) request, is the Curl_add_buffer()
+ series of functions we use. They append data to one single buffer, and when
+ the building is done the entire request is sent off in one single write. This
+ is done this way to overcome problems with flawed firewalls and lame servers.
+
+ FTP
+
+ The Curl_if2ip() function can be used for getting the IP number of a
+ specified network interface, and it resides in lib/if2ip.c.
+
+ Curl_ftpsendf() is used for sending FTP commands to the remote server. It was
+ made a separate function to prevent us programmers from forgetting that they
+ must be CRLF terminated. They must also be sent in one single write() to make
+ firewalls and similar happy.
+
+ Kerberos
+
+ The kerberos support is mainly in lib/krb4.c and lib/security.c.
+
+ TELNET
+
+ Telnet is implemented in lib/telnet.c.
+
+ FILE
+
+ The file:// protocol is dealt with in lib/file.c.
+
+ LDAP
+
+ Everything LDAP is in lib/ldap.c and lib/openldap.c
+
+ GENERAL
+
+ URL encoding and decoding, called escaping and unescaping in the source code,
+ is found in lib/escape.c.
+
+ While transferring data in Transfer() a few functions might get used.
+ curl_getdate() in lib/parsedate.c is for HTTP date comparisons (and more).
+
+ lib/getenv.c offers curl_getenv() which is for reading environment variables
+ in a neat platform independent way. That's used in the client, but also in
+ lib/url.c when checking the proxy environment variables. Note that contrary
+ to the normal unix getenv(), this returns an allocated buffer that must be
+ free()ed after use.
+
+ lib/netrc.c holds the .netrc parser
+
+ lib/timeval.c features replacement functions for systems that don't have
+ gettimeofday() and a few support functions for timeval conversions.
+
+ A function named curl_version() that returns the full curl version string is
+ found in lib/version.c.
+
+Persistent Connections
+======================
+
+ The persistent connection support in libcurl requires some considerations on
+ how to do things inside of the library.
+
+ o The 'SessionHandle' struct returned in the curl_easy_init() call must never
+ 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).
+ o This enables the 'curl handle' to be reused on subsequent transfers.
+ 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.
+
+ The curl handle must be re-used in order for the persistent connections to
+ work.
+
+multi interface/non-blocking
+============================
+
+ 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 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
+=============
+
+ Originally libcurl supported SSLeay for SSL/TLS transports, but that was then
+ extended to its successor OpenSSL but has since also been extended to several
+ other SSL/TLS libraries and we expect and hope to further extend the support
+ in future libcurl versions.
+
+ To deal with this internally in the best way possible, we have a generic SSL
+ function API as provided by the sslgen.[ch] system, and they are the only SSL
+ functions we must use from within libcurl. sslgen is then crafted to use the
+ appropriate lower-level function calls to whatever SSL library that is in
+ use.
+
+Library Symbols
+===============
+
+ All symbols used internally in libcurl must use a 'Curl_' prefix if they're
+ used in more than a single file. Single-file symbols must be made static.
+ Public ("exported") symbols must use a 'curl_' prefix. (There are exceptions,
+ but they are to be changed to follow this pattern in future versions.) Public
+ API functions are marked with CURL_EXTERN in the public header files so that
+ all others can be hidden on platforms where this is possible.
+
+Return Codes and Informationals
+===============================
+
+ I've made things simple. Almost every function in libcurl returns a CURLcode,
+ that must be CURLE_OK if everything is OK or otherwise a suitable error code
+ as the curl/curl.h include file defines. The very spot that detects an error
+ must use the Curl_failf() function to set the human-readable error
+ description.
+
+ In aiding the user to understand what's happening and to debug curl usage, we
+ must supply a fair amount of informational messages by using the Curl_infof()
+ function. Those messages are only displayed when the user explicitly asks for
+ them. They are best used when revealing information that isn't otherwise
+ obvious.
+
+API/ABI
+=======
+
+ We make an effort to not export or show internals or how internals work, as
+ that makes it easier to keep a solid API/ABI over time. See docs/libcurl/ABI
+ for our promise to users.
+
+Client
+======
+
+ 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/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
+ control after the curl_easy_perform() it cleans up the library, checks status
+ and exits.
+
+ When the operation is done, the ourWriteOut() function in src/writeout.c may
+ be called to report about the operation. That function is using the
+ curl_easy_getinfo() function to extract useful information from the curl
+ session.
+
+ It may loop and do all this several times if many URLs were specified on the
+ command line or config file.
+
+Memory Debugging
+================
+
+ The file lib/memdebug.c contains debug-versions of a few functions. Functions
+ such as malloc, free, fopen, fclose, etc that somehow deal with resources
+ that might give us problems if we "leak" them. The functions in the memdebug
+ system do nothing fancy, they do their normal function and then log
+ information about what they just did. The logged data can then be analyzed
+ after a complete session,
+
+ memanalyze.pl is the perl script present in tests/ that analyzes a log file
+ generated by the memory tracking system. It detects if resources are
+ allocated but never freed and other kinds of errors related to resource
+ management.
+
+ Internally, definition of preprocessor symbol DEBUGBUILD restricts code which
+ is only compiled for debug enabled builds. And symbol CURLDEBUG is used to
+ differentiate code which is _only_ used for memory tracking/debugging.
+
+ Use -DCURLDEBUG when compiling to enable memory debugging, this is also
+ switched on by running configure with --enable-curldebug. Use -DDEBUGBUILD
+ when compiling to enable a debug build or run configure with --enable-debug.
+
+ curl --version will list 'Debug' feature for debug enabled builds, and
+ will list 'TrackMemory' feature for curl debug memory tracking capable
+ builds. These features are independent and can be controlled when running
+ the configure script. When --enable-debug is given both features will be
+ enabled, unless some restriction prevents memory tracking from being used.
+
+Test Suite
+==========
+
+ The test suite is placed in its own subdirectory directly off the root in the
+ curl archive tree, and it contains a bunch of scripts and a lot of test case
+ data.
+
+ The main test script is runtests.pl that will invoke test servers like
+ httpserver.pl and ftpserver.pl before all the test cases are performed. The
+ test suite currently only runs on unix-like platforms.
+
+ You'll find a description of the test suite in the tests/README file, and the
+ test case data files in the tests/FILEFORMAT file.
+
+ The test suite automatically detects if curl was built with the memory
+ debugging enabled, and if it was it will detect memory leaks, too.
+
+Building Releases
+=================
+
+ There's no magic to this. When you consider everything stable enough to be
+ released, do this:
+
+ 1. Tag the source code accordingly.
+
+ 2. run the 'maketgz' script (using 'make distcheck' will give you a pretty
+ good view on the status of the current sources). maketgz requires a
+ version number and creates the release archive. maketgz uses 'make dist'
+ for the actual archive building, why you need to fill in the Makefile.am
+ files properly for which files that should be included in the release
+ archives.
+
+ 3. When that's complete, sign the output files.
+
+ 4. Upload
+
+ 5. Update web site and changelog on site
+
+ 6. Send announcement to the mailing lists
+
+ NOTE: you must have curl checked out from git to be able to do a proper
+ release build. The release tarballs do not have everything setup in order to
+ do releases properly.
diff --git a/libs/libcurl/docs/KNOWN_BUGS b/libs/libcurl/docs/KNOWN_BUGS
new file mode 100644
index 0000000000..d53d970d96
--- /dev/null
+++ b/libs/libcurl/docs/KNOWN_BUGS
@@ -0,0 +1,250 @@
+These are problems known to exist at the time of this release. Feel free to
+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=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=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=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
+ forced to close they break the NTLM support.
+
+76. The SOCKET type in Win64 is 64 bits large (and thus so is curl_socket_t on
+ that platform), and long is only 32 bits. It makes it impossible for
+ curl_easy_getinfo() to return a socket properly with the CURLINFO_LASTSOCKET
+ option as for all other operating systems.
+
+75. NTLM authentication involving unicode user name or password only works
+ 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=896
+
+ The schannel version verified to work as mentioned in
+ http://curl.haxx.se/mail/lib-2012-07/0073.html
+
+73. if a connection is made to a FTP server but the server then just never
+ sends the 220 response or otherwise is dead slow, libcurl will not
+ 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=856
+
+72. "Pausing pipeline problems."
+ http://curl.haxx.se/mail/lib-2009-07/0214.html
+
+70. Problem re-using easy handle after call to curl_multi_remove_handle
+ http://curl.haxx.se/mail/lib-2009-07/0249.html
+
+68. "More questions about ares behavior".
+ http://curl.haxx.se/mail/lib-2009-08/0012.html
+
+67. When creating multipart formposts. The file name part can be encoded with
+ something beyond ascii but currently libcurl will only pass in the verbatim
+ string the app provides. There are several browsers that already do this
+ encoding. The key seems to be the updated draft to RFC2231:
+ 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=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
+ for the data transfer isn't more or less instant as the code does not
+ properly wait for the connect to be confirmed. See test case 564 for a first
+ shot at a test case.
+
+63. When CURLOPT_CONNECT_ONLY is used, the handle cannot reliably be re-used
+ for any further requests or transfers. The work-around is then to close that
+ handle with curl_easy_cleanup() and create a new. Some more details:
+ http://curl.haxx.se/mail/lib-2009-04/0300.html
+
+61. If an upload using Expect: 100-continue receives an HTTP 417 response,
+ it ought to be automatically resent without the Expect:. A workaround is
+ for the client application to redo the transfer after disabling Expect:.
+ http://curl.haxx.se/mail/archive-2008-02/0043.html
+
+60. libcurl closes the connection if an HTTP 401 reply is received while it
+ is waiting for the the 100-continue response.
+ http://curl.haxx.se/mail/lib-2008-08/0462.html
+
+58. It seems sensible to be able to use CURLOPT_NOBODY and
+ 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
+
+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=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
+ to the KfW library. See ticket #5601 at http://krbdev.mit.edu/rt/
+
+52. Gautam Kachroo's issue that identifies a problem with the multi interface
+ where a connection can be re-used without actually being properly
+ SSL-negotiated:
+ http://curl.haxx.se/mail/lib-2008-01/0277.html
+
+49. If using --retry and the transfer timeouts (possibly due to using -m or
+ -y/-Y) the next attempt doesn't resume the transfer properly from what was
+ downloaded in the previous attempt but will truncate and restart at the
+ original position where it was at before the previous failed attempt. See
+ http://curl.haxx.se/mail/lib-2008-01/0080.html and Mandriva bug report
+ https://qa.mandriva.com/show_bug.cgi?id=22565
+
+48. If a CONNECT response-headers are larger than BUFSIZE (16KB) when the
+ connection is meant to be kept alive (like for NTLM proxy auth), the
+ function will return prematurely and will confuse the rest of the HTTP
+ 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=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=635
+
+39. Steffen Rumler's Race Condition in Curl_proxyCONNECT:
+ http://curl.haxx.se/mail/lib-2007-01/0045.html
+
+38. Kumar Swamy Bhatt's problem in ftp/ssl "LIST" operation:
+ http://curl.haxx.se/mail/lib-2007-01/0103.html
+
+35. Both SOCKS5 and SOCKS4 proxy connections are done blocking, which is very
+ bad when used with the multi interface.
+
+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=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
+ --cflags suffers from the same effects with CFLAGS/CPPFLAGS.
+
+30. You need to use -g to the command line tool in order to use RFC2732-style
+ IPv6 numerical addresses in URLs.
+
+29. IPv6 URLs with zone ID is not nicely supported.
+ http://www.ietf.org/internet-drafts/draft-fenner-literal-zone-02.txt (expired)
+ specifies the use of a plus sign instead of a percent when specifying zone
+ 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):
+ 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=535
+
+23. SOCKS-related problems:
+ B) libcurl doesn't support FTPS over a SOCKS proxy.
+ E) libcurl doesn't support active FTP over a SOCKS proxy
+
+ We probably have even more bugs and lack of features when a SOCKS proxy is
+ used.
+
+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:
+
+ The sender converts the data from an internal character representation to
+ the standard 8-bit NVT-ASCII representation (see the Telnet
+ specification). The receiver will convert the data from the standard
+ form to his own internal form.
+
+ Since 7.15.4 at least line endings are converted.
+
+16. FTP URLs passed to curl may contain NUL (0x00) in the RFC 1738 <user>,
+ <password>, and <fpath> components, encoded as "%00". The problem is that
+ curl_unescape does not detect this, but instead returns a shortened C
+ string. From a strict FTP protocol standpoint, NUL is a valid character
+ within RFC 959 <string>, so the way to handle this correctly in curl would
+ be to use a data structure other than a plain C string, one that can handle
+ embedded NUL characters. From a practical standpoint, most FTP servers
+ would not meaningfully support NUL characters within RFC 959 <string>,
+ anyway (e.g., UNIX pathnames may not contain NUL).
+
+14. Test case 165 might fail on a system which has libidn present, but with an
+ old iconv version (2.1.3 is a known bad version), since it doesn't recognize
+ the charset when named ISO8859-1. Changing the name to ISO-8859-1 makes the
+ test pass, but instead makes it fail on Solaris hosts that use its native
+ iconv.
+
+13. curl version 7.12.2 fails on AIX if compiled with --enable-ares.
+ The workaround is to combine --enable-ares with --disable-shared
+
+12. When connecting to a SOCKS proxy, the (connect) timeout is not properly
+ acknowledged after the actual TCP connect (during the SOCKS "negotiate"
+ phase).
+
+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=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
+ doesn't do a HEAD first to get the initial size. This needs to be done
+ manually for HTTP PUT resume to work, and then '-C [index]'.
+
+6. libcurl ignores empty path parts in FTP URLs, whereas RFC1738 states that
+ such parts should be sent to the server as 'CWD ' (without an argument).
+ The only exception to this rule, is that we knowingly break this if the
+ empty part is first in the path, as then we use the double slashes to
+ indicate that the user wants to reach the root dir (this exception SHALL
+ remain even when this bug is fixed).
+
+5. libcurl doesn't treat the content-length of compressed data properly, as
+ it seems HTTP servers send the *uncompressed* length in that header and
+ libcurl thinks of it as the *compressed* length. Some explanations are here:
+ http://curl.haxx.se/mail/lib-2003-06/0146.html
+
+2. If a HTTP server responds to a HEAD request and includes a body (thus
+ violating the RFC2616), curl won't wait to read the response but just stop
+ reading and return back. If a second request (let's assume a GET) is then
+ immediately made to the same server again, the connection will be re-used
+ fine of course, and the second request will be sent off but when the
+ response is to get read, the previous response-body is what curl will read
+ and havoc is what happens.
+ More details on this is found in this libcurl mailing list thread:
+ http://curl.haxx.se/mail/lib-2002-08/0000.html
diff --git a/libs/libcurl/docs/LICENSE-MIXING b/libs/libcurl/docs/LICENSE-MIXING
new file mode 100644
index 0000000000..f596546da5
--- /dev/null
+++ b/libs/libcurl/docs/LICENSE-MIXING
@@ -0,0 +1,130 @@
+ License Mixing with apps, libcurl and Third Party Libraries
+ ===========================================================
+
+libcurl can be built to use a fair amount of various third party libraries,
+libraries that are written and provided by other parties that are distributed
+using their own licenses. Even libcurl itself contains code that may cause
+problems to some. This document attempts to describe what licenses libcurl and
+the other libraries use and what possible dilemmas linking and mixing them all
+can lead to for end users.
+
+I am not a lawyer and this is not legal advice!
+
+One common dilemma is that GPL[1]-licensed code is not allowed to be linked
+with code licensed under the Original BSD license (with the announcement
+clause). You may still build your own copies that use them all, but
+distributing them as binaries would be to violate the GPL license - unless you
+accompany your license with an exception[2]. This particular problem was
+addressed when the Modified BSD license was created, which does not have the
+announcement clause that collides with GPL.
+
+libcurl http://curl.haxx.se/docs/copyright.html
+
+ Uses an MIT (or Modified BSD)-style license that is as liberal as
+ possible. Some of the source files that deal with KRB4 have Original
+ BSD-style announce-clause licenses. You may not distribute binaries
+ with krb4-enabled libcurl that also link with GPL-licensed code!
+
+OpenSSL http://www.openssl.org/source/license.html
+
+ (May be used for SSL/TLS support) Uses an Original BSD-style license
+ with an announcement clause that makes it "incompatible" with GPL. You
+ are not allowed to ship binaries that link with OpenSSL that includes
+ GPL code (unless that specific GPL code includes an exception for
+ OpenSSL - a habit that is growing more and more common). If OpenSSL's
+ licensing is a problem for you, consider using GnuTLS or yassl
+ instead.
+
+GnuTLS http://www.gnutls.org/
+
+ (May be used for SSL/TLS support) Uses the LGPL[3] license. If this is
+ a problem for you, consider using OpenSSL instead. Also note that
+ GnuTLS itself depends on and uses other libs (libgcrypt and
+ libgpg-error) and they too are LGPL- or GPL-licensed.
+
+yassl http://www.yassl.com/
+
+ (May be used for SSL/TLS support) Uses the GPL[1] license. If this is
+ a problem for you, consider using OpenSSL or GnuTLS instead.
+
+NSS http://www.mozilla.org/projects/security/pki/nss/
+
+ (May be used for SSL/TLS support) Is covered by the MPL[4] license,
+ the GPL[1] license and the LGPL[3] license. You may choose to license
+ the code under MPL terms, GPL terms, or LGPL terms. These licenses
+ grant you different permissions and impose different obligations. You
+ should select the license that best meets your needs.
+
+axTLS http://axtls.sourceforge.net/
+
+ (May be used for SSL/TLS support) Uses a Modified BSD-style license.
+
+c-ares http://daniel.haxx.se/projects/c-ares/license.html
+
+ (Used for asynchronous name resolves) Uses an MIT license that is very
+ liberal and imposes no restrictions on any other library or part you
+ may link with.
+
+zlib http://www.gzip.org/zlib/zlib_license.html
+
+ (Used for compressed Transfer-Encoding support) Uses an MIT-style
+ license that shouldn't collide with any other library.
+
+krb4
+
+ While nothing in particular says that a Kerberos4 library must use any
+ particular license, the one I've tried and used successfully so far
+ (kth-krb4) is partly Original BSD-licensed with the announcement
+ clause. Some of the code in libcurl that is written to deal with
+ Kerberos4 is Modified BSD-licensed.
+
+MIT Kerberos http://web.mit.edu/kerberos/www/dist/
+
+ (May be used for GSS support) MIT licensed, that shouldn't collide
+ with any other parts.
+
+Heimdal http://www.pdc.kth.se/heimdal/
+
+ (May be used for GSS support) Heimdal is Original BSD licensed with
+ the announcement clause.
+
+GNU GSS http://www.gnu.org/software/gss/
+
+ (May be used for GSS support) GNU GSS is GPL licensed. Note that you
+ may not distribute binary curl packages that uses this if you build
+ curl to also link and use any Original BSD licensed libraries!
+
+fbopenssl
+
+ (Used for SPNEGO support) Unclear license. Based on its name, I assume
+ that it uses the OpenSSL license and thus shares the same issues as
+ described for OpenSSL above.
+
+libidn http://josefsson.org/libidn/
+
+ (Used for IDNA support) Uses the GNU Lesser General Public
+ License [3]. LGPL is a variation of GPL with slightly less aggressive
+ "copyleft". This license requires more requirements to be met when
+ distributing binaries, see the license for details. Also note that if
+ you distribute a binary that includes this library, you must also
+ include the full LGPL license text. Please properly point out what
+ parts of the distributed package that the license addresses.
+
+OpenLDAP http://www.openldap.org/software/release/license.html
+
+ (Used for LDAP support) Uses a Modified BSD-style license. Since
+ libcurl uses OpenLDAP as a shared library only, I have not heard of
+ anyone that ships OpenLDAP linked with libcurl in an app.
+
+libssh2 http://www.libssh2.org/
+
+ (Used for scp and sftp support) libssh2 uses a Modified BSD-style
+ license.
+
+[1] = GPL - GNU General Public License: http://www.gnu.org/licenses/gpl.html
+[2] = http://www.fsf.org/licenses/gpl-faq.html#GPLIncompatibleLibs details on
+ how to write such an exception to the GPL
+[3] = LGPL - GNU Lesser General Public License:
+ http://www.gnu.org/licenses/lgpl.html
+[4] = MPL - Mozilla Public License:
+ http://www.mozilla.org/MPL/
diff --git a/libs/libcurl/docs/MAIL-ETIQUETTE b/libs/libcurl/docs/MAIL-ETIQUETTE
new file mode 100644
index 0000000000..ae1821a89b
--- /dev/null
+++ b/libs/libcurl/docs/MAIL-ETIQUETTE
@@ -0,0 +1,228 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+MAIL ETIQUETTE
+
+ 1. About the lists
+ 1.1 Mailing Lists
+ 1.2 Netiquette
+ 1.3 Do Not Mail a Single Individual
+ 1.4 Subscription Required
+ 1.5 Moderation of new posters
+ 1.6 Handling trolls and spam
+ 1.7 How to unsubscribe
+
+ 2. Sending mail
+ 2.1 Reply or New Mail
+ 2.2 Reply to the List
+ 2.3 Use a Sensible Subject
+ 2.4 Do Not Top-Post
+ 2.5 HTML is not for mails
+ 2.6 Quoting
+ 2.7 Digest
+ 2.8 Please Tell Us How You Solved The Problem!
+
+==============================================================================
+
+1. About the lists
+
+ 1.1 Mailing Lists
+
+ The mailing lists we have are all listed and described at
+ http://curl.haxx.se/mail/
+
+ Each mailing list is targeted to a specific set of users and subjects,
+ please use the one or the ones that suit you the most.
+
+ Each mailing list have hundreds up to thousands of readers, meaning that
+ each mail sent will be received and read by a very large amount of people.
+ People from various cultures, regions, religions and continents.
+
+ 1.2 Netiquette
+
+ Netiquette is a common name for how to behave on the internet. Of course, in
+ each particular group and subculture there will be differences in what is
+ acceptable and what is considered good manners.
+
+ This document outlines what we in the cURL project considers to be good
+ etiquette, and primarily this focus on how to behave on and how to use our
+ mailing lists.
+
+ 1.3 Do Not Mail a Single Individual
+
+ Many people send one question to one person. One person gets many mails, and
+ there is only one person who can give you a reply. The question may be
+ something that other people are also wanting to ask. These other people have
+ no way to read the reply, but to ask the one person the question. The one
+ person consequently gets overloaded with mail.
+
+ If you really want to contact an individual and perhaps pay for his or her
+ services, by all means go ahead, but if it's just another curl question,
+ take it to a suitable list instead.
+
+ 1.4 Subscription Required
+
+ All curl mailing lists require that you are subscribed to allow a mail to go
+ through to all the subscribers.
+
+ If you post without being subscribed (or from a different mail address than
+ the one you are subscribed with), your mail will simply be silently
+ discarded. You have to subscribe first, then post.
+
+ The reason for this unfortunate and strict subscription policy is of course
+ to stop spam from pestering the lists.
+
+ 1.5 Moderation of new posters
+
+ Several of the curl mailing lists automatically make all posts from new
+ subscribers require moderation. This means that after you've subscribed and
+ send your first mail to a list, that mail will not be let through to the
+ list until a mailing list administrator has verified that it is OK and
+ permits it to get posted.
+
+ Once a first post has been made that proves the sender is actually talking
+ about curl-related subjects, the moderation "flag" will be switched off and
+ future posts will go through without being moderated.
+
+ The reason for this moderation policy is that we do suffer from spammers who
+ actually subscribe and send spam to our lists.
+
+ 1.6 Handling trolls and spam
+
+ Despite our good intentions and hard work to keep spam off the lists and to
+ maintain a friendly and positive atmosphere, there will be times when spam
+ and or trolls get through.
+
+ Troll - "someone who posts inflammatory, extraneous, or off-topic messages
+ in an online community"
+
+ Spam - "use of electronic messaging systems to send unsolicited bulk
+ messages"
+
+ No matter what, we NEVER EVER respond to trolls or spammers on the list. If
+ you believe the list admin should do something particular, contact him/her
+ off-list. The subject will be taken care of as good as possible to prevent
+ repeated offences, but responding on the list to such messages never lead to
+ anything good and only puts the light even more on the offender: which was
+ the entire purpose of it getting to the list in the first place.
+
+ Don't feed the trolls!
+
+ 1.7 How to unsubscribe
+
+ You unsubscribe the same way you subscribed in the first place. You go to
+ the page for the particular mailing list you're subscribed to and you enter
+ your email address and password and press the unsubscribe button.
+
+ Also, this information is included in the headers of every mail that is sent
+ out to all curl related mailing lists and there's footer in each mail that
+ links to the "admin" page on which you can unsubscribe and change other
+ options.
+
+ You NEVER EVER email the mailing list requesting someone else to get you off
+ the list.
+
+
+2. Sending mail
+
+ 2.1 Reply or New Mail
+
+ Please do not reply to an existing message as a short-cut to post a message
+ to the lists.
+
+ Many mail programs and web archivers use information within mails to keep
+ them together as "threads", as collections of posts that discuss a certain
+ subject. If you don't intend to reply on the same or similar subject, don't
+ just hit reply on an existing mail and change subject, create a new mail.
+
+ 2.2 Reply to the List
+
+ When replying to a message from the list, make sure that you do "group
+ reply" or "reply to all", and not just reply to the author of the single
+ mail you reply to.
+
+ We're actively discouraging replying back to the single person by setting
+ the Reply-To: field in outgoing mails back to the mailing list address,
+ making it harder for people to mail the author only by mistake.
+
+ 2.3 Use a Sensible Subject
+
+ Please use a subject of the mail that makes sense and that is related to the
+ contents of your mail. It makes it a lot easier to find your mail afterwards
+ and it makes it easier to track mail threads and topics.
+
+ 2.4 Do Not Top-Post
+
+ If you reply to a message, don't use top-posting. Top-posting is when you
+ write the new text at the top of a mail and you insert the previous quoted
+ mail conversation below. It forces users to read the mail in a backwards
+ order to properly understand it.
+
+ This is why top posting is so bad:
+
+ A: Because it messes up the order in which people normally read
+ text.
+ Q: Why is top-posting such a bad thing?
+ A: Top-posting.
+ Q: What is the most annoying thing in e-mail?
+
+ Apart from the screwed up read order (especially when mixed together in a
+ thread when someone responds using the mandated bottom-posting style), it
+ also makes it impossible to quote only parts of the original mail.
+
+ When you reply to a mail. You let the mail client insert the previous mail
+ quoted. Then you put the cursor on the first line of the mail and you move
+ down through the mail, deleting all parts of the quotes that don't add
+ context for your comments. When you want to add a comment you do so, inline,
+ right after the quotes that relate to your comment. Then you continue
+ downwards again.
+
+ When most of the quotes have been removed and you've added your own words,
+ you're done!
+
+ 2.5 HTML is not for mails
+
+ Please switch off those HTML encoded messages. You can mail all those funny
+ mails to your friends. We speak plain text mails.
+
+ 2.6 Quoting
+
+ Quote as little as possible. Just enough to provide the context you cannot
+ leave out. A lengthy description can be found here:
+
+ http://www.netmeister.org/news/learn2quote.html
+
+ 2.7 Digest
+
+ We allow subscribers to subscribe to the "digest" version of the mailing
+ lists. A digest is a collection of mails lumped together in one single mail.
+
+ Should you decide to reply to a mail sent out as a digest, there are two
+ things you MUST consider if you really really cannot subscribe normally
+ instead:
+
+ Cut off all mails and chatter that is not related to the mail you want to
+ reply to.
+
+ Change the subject name to something sensible and related to the subject,
+ preferably even the actual subject of the single mail you wanted to reply to
+
+ 2.8 Please Tell Us How You Solved The Problem!
+
+ Many people mail questions to the list, people spend some of their time and
+ make an effort in providing good answers to these questions.
+
+ If you are the one who asks, please consider responding once more in case
+ one of the hints was what solved your problems. The guys who write answers
+ feel good to know that they provided a good answer and that you fixed the
+ problem. Far too often, the person who asked the question is never heard of
+ again, and we never get to know if he/she is gone because the problem was
+ solved or perhaps because the problem was unsolvable!
+
+ Getting the solution posted also helps other users that experience the same
+ problem(s). They get to see (possibly in the web archives) that the
+ suggested fixes actually has helped at least one person.
+
diff --git a/libs/libcurl/docs/MANUAL b/libs/libcurl/docs/MANUAL
new file mode 100644
index 0000000000..4ad2e135e3
--- /dev/null
+++ b/libs/libcurl/docs/MANUAL
@@ -0,0 +1,1023 @@
+LATEST VERSION
+
+ You always find news about what's going on as well as the latest versions
+ from the curl web pages, located at:
+
+ http://curl.haxx.se
+
+SIMPLE USAGE
+
+ Get the main page from Netscape's web-server:
+
+ curl http://www.netscape.com/
+
+ Get the README file the user's home directory at funet's ftp-server:
+
+ curl ftp://ftp.funet.fi/README
+
+ Get a web page from a server using port 8000:
+
+ curl http://www.weirdserver.com:8000/
+
+ Get a directory listing of an FTP site:
+
+ curl ftp://cool.haxx.se/
+
+ Get the definition of curl from a dictionary:
+
+ curl dict://dict.org/m:curl
+
+ Fetch two documents at once:
+
+ curl ftp://cool.haxx.se/ http://www.weirdserver.com:8000/
+
+ Get a file off an FTPS server:
+
+ curl ftps://files.are.secure.com/secrets.txt
+
+ or use the more appropriate FTPS way to get the same file:
+
+ curl --ftp-ssl ftp://files.are.secure.com/secrets.txt
+
+ Get a file from an SSH server using SFTP:
+
+ curl -u username sftp://shell.example.com/etc/issue
+
+ Get a file from an SSH server using SCP using a private key to authenticate:
+
+ curl -u username: --key ~/.ssh/id_dsa --pubkey ~/.ssh/id_dsa.pub \
+ scp://shell.example.com/~/personal.txt
+
+ Get the main page from an IPv6 web server:
+
+ curl -g "http://[2001:1890:1112:1::20]/"
+
+DOWNLOAD TO A FILE
+
+ Get a web page and store in a local file with a specific name:
+
+ curl -o thatpage.html http://www.netscape.com/
+
+ Get a web page and store in a local file, make the local file get the name
+ of the remote document (if no file name part is specified in the URL, this
+ will fail):
+
+ curl -O http://www.netscape.com/index.html
+
+ Fetch two files and store them with their remote names:
+
+ curl -O www.haxx.se/index.html -O curl.haxx.se/download.html
+
+USING PASSWORDS
+
+ FTP
+
+ To ftp files using name+passwd, include them in the URL like:
+
+ curl ftp://name:passwd@machine.domain:port/full/path/to/file
+
+ or specify them with the -u flag like
+
+ curl -u name:passwd ftp://machine.domain:port/full/path/to/file
+
+ FTPS
+
+ It is just like for FTP, but you may also want to specify and use
+ SSL-specific options for certificates etc.
+
+ Note that using FTPS:// as prefix is the "implicit" way as described in the
+ standards while the recommended "explicit" way is done by using FTP:// and
+ the --ftp-ssl option.
+
+ SFTP / SCP
+
+ This is similar to FTP, but you can specify a private key to use instead of
+ a password. Note that the private key may itself be protected by a password
+ that is unrelated to the login password of the remote system. If you
+ provide a private key file you must also provide a public key file.
+
+ HTTP
+
+ Curl also supports user and password in HTTP URLs, thus you can pick a file
+ like:
+
+ curl http://name:passwd@machine.domain/full/path/to/file
+
+ or specify user and password separately like in
+
+ curl -u name:passwd http://machine.domain/full/path/to/file
+
+ HTTP offers many different methods of authentication and curl supports
+ several: Basic, Digest, NTLM and Negotiate. Without telling which method to
+ use, curl defaults to Basic. You can also ask curl to pick the most secure
+ ones out of the ones that the server accepts for the given URL, by using
+ --anyauth.
+
+ NOTE! According to the URL specification, HTTP URLs can not contain a user
+ and password, so that style will not work when using curl via a proxy, even
+ though curl allows it at other times. When using a proxy, you _must_ use
+ the -u style for user and password.
+
+ HTTPS
+
+ Probably most commonly used with private certificates, as explained below.
+
+PROXY
+
+ curl supports both HTTP and SOCKS proxy servers, with optional authentication.
+ It does not have special support for FTP proxy servers since there are no
+ standards for those, but it can still be made to work with many of them. You
+ can also use both HTTP and SOCKS proxies to transfer files to and from FTP
+ servers.
+
+ Get an ftp file using an HTTP proxy named my-proxy that uses port 888:
+
+ curl -x my-proxy:888 ftp://ftp.leachsite.com/README
+
+ Get a file from an HTTP server that requires user and password, using the
+ same proxy as above:
+
+ curl -u user:passwd -x my-proxy:888 http://www.get.this/
+
+ Some proxies require special authentication. Specify by using -U as above:
+
+ curl -U user:passwd -x my-proxy:888 http://www.get.this/
+
+ A comma-separated list of hosts and domains which do not use the proxy can
+ be specified as:
+
+ curl --noproxy localhost,get.this -x my-proxy:888 http://www.get.this/
+
+ If the proxy is specified with --proxy1.0 instead of --proxy or -x, then
+ curl will use HTTP/1.0 instead of HTTP/1.1 for any CONNECT attempts.
+
+ curl also supports SOCKS4 and SOCKS5 proxies with --socks4 and --socks5.
+
+ See also the environment variables Curl supports that offer further proxy
+ control.
+
+ Most FTP proxy servers are set up to appear as a normal FTP server from the
+ client's perspective, with special commands to select the remote FTP server.
+ curl supports the -u, -Q and --ftp-account options that can be used to
+ set up transfers through many FTP proxies. For example, a file can be
+ uploaded to a remote FTP server using a Blue Coat FTP proxy with the
+ options:
+
+ curl -u "Remote-FTP-Username@remote.ftp.server Proxy-Username:Remote-Pass" \
+ --ftp-account Proxy-Password --upload-file local-file \
+ ftp://my-ftp.proxy.server:21/remote/upload/path/
+
+ See the manual for your FTP proxy to determine the form it expects to set up
+ transfers, and curl's -v option to see exactly what curl is sending.
+
+RANGES
+
+ HTTP 1.1 introduced byte-ranges. Using this, a client can request
+ to get only one or more subparts of a specified document. Curl supports
+ this with the -r flag.
+
+ Get the first 100 bytes of a document:
+
+ curl -r 0-99 http://www.get.this/
+
+ Get the last 500 bytes of a document:
+
+ curl -r -500 http://www.get.this/
+
+ Curl also supports simple ranges for FTP files as well. Then you can only
+ specify start and stop position.
+
+ Get the first 100 bytes of a document using FTP:
+
+ curl -r 0-99 ftp://www.get.this/README
+
+UPLOADING
+
+ FTP / FTPS / SFTP / SCP
+
+ Upload all data on stdin to a specified server:
+
+ curl -T - ftp://ftp.upload.com/myfile
+
+ Upload data from a specified file, login with user and password:
+
+ curl -T uploadfile -u user:passwd ftp://ftp.upload.com/myfile
+
+ Upload a local file to the remote site, and use the local file name at the remote
+ site too:
+
+ curl -T uploadfile -u user:passwd ftp://ftp.upload.com/
+
+ Upload a local file to get appended to the remote file:
+
+ curl -T localfile -a ftp://ftp.upload.com/remotefile
+
+ Curl also supports ftp upload through a proxy, but only if the proxy is
+ configured to allow that kind of tunneling. If it does, you can run curl in
+ a fashion similar to:
+
+ curl --proxytunnel -x proxy:port -T localfile ftp.upload.com
+
+ HTTP
+
+ Upload all data on stdin to a specified HTTP site:
+
+ curl -T - http://www.upload.com/myfile
+
+ Note that the HTTP server must have been configured to accept PUT before
+ this can be done successfully.
+
+ For other ways to do HTTP data upload, see the POST section below.
+
+VERBOSE / DEBUG
+
+ If curl fails where it isn't supposed to, if the servers don't let you in,
+ if you can't understand the responses: use the -v flag to get verbose
+ fetching. Curl will output lots of info and what it sends and receives in
+ order to let the user see all client-server interaction (but it won't show
+ you the actual data).
+
+ curl -v ftp://ftp.upload.com/
+
+ To get even more details and information on what curl does, try using the
+ --trace or --trace-ascii options with a given file name to log to, like
+ this:
+
+ curl --trace trace.txt www.haxx.se
+
+
+DETAILED INFORMATION
+
+ Different protocols provide different ways of getting detailed information
+ about specific files/documents. To get curl to show detailed information
+ about a single file, you should use -I/--head option. It displays all
+ available info on a single file for HTTP and FTP. The HTTP information is a
+ lot more extensive.
+
+ For HTTP, you can get the header information (the same as -I would show)
+ shown before the data by using -i/--include. Curl understands the
+ -D/--dump-header option when getting files from both FTP and HTTP, and it
+ will then store the headers in the specified file.
+
+ Store the HTTP headers in a separate file (headers.txt in the example):
+
+ curl --dump-header headers.txt curl.haxx.se
+
+ Note that headers stored in a separate file can be very useful at a later
+ time if you want curl to use cookies sent by the server. More about that in
+ the cookies section.
+
+POST (HTTP)
+
+ It's easy to post data using curl. This is done using the -d <data>
+ option. The post data must be urlencoded.
+
+ Post a simple "name" and "phone" guestbook.
+
+ curl -d "name=Rafael%20Sagula&phone=3320780" \
+ http://www.where.com/guest.cgi
+
+ How to post a form with curl, lesson #1:
+
+ Dig out all the <input> tags in the form that you want to fill in. (There's
+ a perl program called formfind.pl on the curl site that helps with this).
+
+ If there's a "normal" post, you use -d to post. -d takes a full "post
+ string", which is in the format
+
+ <variable1>=<data1>&<variable2>=<data2>&...
+
+ The 'variable' names are the names set with "name=" in the <input> tags, and
+ the data is the contents you want to fill in for the inputs. The data *must*
+ be properly URL encoded. That means you replace space with + and that you
+ replace weird letters with %XX where XX is the hexadecimal representation of
+ the letter's ASCII code.
+
+ Example:
+
+ (page located at http://www.formpost.com/getthis/
+
+ <form action="post.cgi" method="post">
+ <input name=user size=10>
+ <input name=pass type=password size=10>
+ <input name=id type=hidden value="blablabla">
+ <input name=ding value="submit">
+ </form>
+
+ We want to enter user 'foobar' with password '12345'.
+
+ To post to this, you enter a curl command line like:
+
+ curl -d "user=foobar&pass=12345&id=blablabla&ding=submit" (continues)
+ http://www.formpost.com/getthis/post.cgi
+
+
+ While -d uses the application/x-www-form-urlencoded mime-type, generally
+ understood by CGI's and similar, curl also supports the more capable
+ multipart/form-data type. This latter type supports things like file upload.
+
+ -F accepts parameters like -F "name=contents". If you want the contents to
+ be read from a file, use <@filename> as contents. When specifying a file,
+ you can also specify the file content type by appending ';type=<mime type>'
+ to the file name. You can also post the contents of several files in one
+ field. For example, the field name 'coolfiles' is used to send three files,
+ with different content types using the following syntax:
+
+ curl -F "coolfiles=@fil1.gif;type=image/gif,fil2.txt,fil3.html" \
+ http://www.post.com/postit.cgi
+
+ If the content-type is not specified, curl will try to guess from the file
+ extension (it only knows a few), or use the previously specified type (from
+ an earlier file if several files are specified in a list) or else it will
+ use the default type 'application/octet-stream'.
+
+ Emulate a fill-in form with -F. Let's say you fill in three fields in a
+ form. One field is a file name which to post, one field is your name and one
+ field is a file description. We want to post the file we have written named
+ "cooltext.txt". To let curl do the posting of this data instead of your
+ favourite browser, you have to read the HTML source of the form page and
+ find the names of the input fields. In our example, the input field names
+ are 'file', 'yourname' and 'filedescription'.
+
+ curl -F "file=@cooltext.txt" -F "yourname=Daniel" \
+ -F "filedescription=Cool text file with cool text inside" \
+ http://www.post.com/postit.cgi
+
+ To send two files in one post you can do it in two ways:
+
+ 1. Send multiple files in a single "field" with a single field name:
+
+ curl -F "pictures=@dog.gif,cat.gif"
+
+ 2. Send two fields with two field names:
+
+ curl -F "docpicture=@dog.gif" -F "catpicture=@cat.gif"
+
+ To send a field value literally without interpreting a leading '@'
+ or '<', or an embedded ';type=', use --form-string instead of
+ -F. This is recommended when the value is obtained from a user or
+ some other unpredictable source. Under these circumstances, using
+ -F instead of --form-string would allow a user to trick curl into
+ uploading a file.
+
+REFERRER
+
+ An HTTP request has the option to include information about which address
+ referred it to the actual page. Curl allows you to specify the
+ referrer to be used on the command line. It is especially useful to
+ fool or trick stupid servers or CGI scripts that rely on that information
+ being available or contain certain data.
+
+ curl -e www.coolsite.com http://www.showme.com/
+
+ NOTE: The Referer: [sic] field is defined in the HTTP spec to be a full URL.
+
+USER AGENT
+
+ An HTTP request has the option to include information about the browser
+ that generated the request. Curl allows it to be specified on the command
+ line. It is especially useful to fool or trick stupid servers or CGI
+ scripts that only accept certain browsers.
+
+ Example:
+
+ curl -A 'Mozilla/3.0 (Win95; I)' http://www.nationsbank.com/
+
+ Other common strings:
+ 'Mozilla/3.0 (Win95; I)' Netscape Version 3 for Windows 95
+ 'Mozilla/3.04 (Win95; U)' Netscape Version 3 for Windows 95
+ 'Mozilla/2.02 (OS/2; U)' Netscape Version 2 for OS/2
+ 'Mozilla/4.04 [en] (X11; U; AIX 4.2; Nav)' NS for AIX
+ 'Mozilla/4.05 [en] (X11; U; Linux 2.0.32 i586)' NS for Linux
+
+ Note that Internet Explorer tries hard to be compatible in every way:
+ 'Mozilla/4.0 (compatible; MSIE 4.01; Windows 95)' MSIE for W95
+
+ Mozilla is not the only possible User-Agent name:
+ 'Konqueror/1.0' KDE File Manager desktop client
+ 'Lynx/2.7.1 libwww-FM/2.14' Lynx command line browser
+
+COOKIES
+
+ Cookies are generally used by web servers to keep state information at the
+ client's side. The server sets cookies by sending a response line in the
+ headers that looks like 'Set-Cookie: <data>' where the data part then
+ typically contains a set of NAME=VALUE pairs (separated by semicolons ';'
+ like "NAME1=VALUE1; NAME2=VALUE2;"). The server can also specify for what
+ path the "cookie" should be used for (by specifying "path=value"), when the
+ cookie should expire ("expire=DATE"), for what domain to use it
+ ("domain=NAME") and if it should be used on secure connections only
+ ("secure").
+
+ If you've received a page from a server that contains a header like:
+ Set-Cookie: sessionid=boo123; path="/foo";
+
+ it means the server wants that first pair passed on when we get anything in
+ a path beginning with "/foo".
+
+ Example, get a page that wants my name passed in a cookie:
+
+ curl -b "name=Daniel" www.sillypage.com
+
+ Curl also has the ability to use previously received cookies in following
+ sessions. If you get cookies from a server and store them in a file in a
+ manner similar to:
+
+ curl --dump-header headers www.example.com
+
+ ... you can then in a second connect to that (or another) site, use the
+ cookies from the 'headers' file like:
+
+ curl -b headers www.example.com
+
+ While saving headers to a file is a working way to store cookies, it is
+ however error-prone and not the preferred way to do this. Instead, make curl
+ save the incoming cookies using the well-known netscape cookie format like
+ this:
+
+ curl -c cookies.txt www.example.com
+
+ Note that by specifying -b you enable the "cookie awareness" and with -L
+ you can make curl follow a location: (which often is used in combination
+ with cookies). So that if a site sends cookies and a location, you can
+ use a non-existing file to trigger the cookie awareness like:
+
+ curl -L -b empty.txt www.example.com
+
+ The file to read cookies from must be formatted using plain HTTP headers OR
+ as netscape's cookie file. Curl will determine what kind it is based on the
+ file contents. In the above command, curl will parse the header and store
+ the cookies received from www.example.com. curl will send to the server the
+ stored cookies which match the request as it follows the location. The
+ file "empty.txt" may be a nonexistent file.
+
+ Alas, to both read and write cookies from a netscape cookie file, you can
+ set both -b and -c to use the same file:
+
+ curl -b cookies.txt -c cookies.txt www.example.com
+
+PROGRESS METER
+
+ The progress meter exists to show a user that something actually is
+ happening. The different fields in the output have the following meaning:
+
+ % Total % Received % Xferd Average Speed Time Curr.
+ Dload Upload Total Current Left Speed
+ 0 151M 0 38608 0 0 9406 0 4:41:43 0:00:04 4:41:39 9287
+
+ From left-to-right:
+ % - percentage completed of the whole transfer
+ Total - total size of the whole expected transfer
+ % - percentage completed of the download
+ Received - currently downloaded amount of bytes
+ % - percentage completed of the upload
+ Xferd - currently uploaded amount of bytes
+ Average Speed
+ Dload - the average transfer speed of the download
+ Average Speed
+ Upload - the average transfer speed of the upload
+ Time Total - expected time to complete the operation
+ Time Current - time passed since the invoke
+ Time Left - expected time left to completion
+ Curr.Speed - the average transfer speed the last 5 seconds (the first
+ 5 seconds of a transfer is based on less time of course.)
+
+ The -# option will display a totally different progress bar that doesn't
+ need much explanation!
+
+SPEED LIMIT
+
+ Curl allows the user to set the transfer speed conditions that must be met
+ to let the transfer keep going. By using the switch -y and -Y you
+ can make curl abort transfers if the transfer speed is below the specified
+ lowest limit for a specified time.
+
+ To have curl abort the download if the speed is slower than 3000 bytes per
+ second for 1 minute, run:
+
+ curl -Y 3000 -y 60 www.far-away-site.com
+
+ This can very well be used in combination with the overall time limit, so
+ that the above operation must be completed in whole within 30 minutes:
+
+ curl -m 1800 -Y 3000 -y 60 www.far-away-site.com
+
+ Forcing curl not to transfer data faster than a given rate is also possible,
+ which might be useful if you're using a limited bandwidth connection and you
+ don't want your transfer to use all of it (sometimes referred to as
+ "bandwidth throttle").
+
+ Make curl transfer data no faster than 10 kilobytes per second:
+
+ curl --limit-rate 10K www.far-away-site.com
+
+ or
+
+ curl --limit-rate 10240 www.far-away-site.com
+
+ Or prevent curl from uploading data faster than 1 megabyte per second:
+
+ curl -T upload --limit-rate 1M ftp://uploadshereplease.com
+
+ When using the --limit-rate option, the transfer rate is regulated on a
+ per-second basis, which will cause the total transfer speed to become lower
+ than the given number. Sometimes of course substantially lower, if your
+ transfer stalls during periods.
+
+CONFIG FILE
+
+ Curl automatically tries to read the .curlrc file (or _curlrc file on win32
+ systems) from the user's home dir on startup.
+
+ The config file could be made up with normal command line switches, but you
+ can also specify the long options without the dashes to make it more
+ readable. You can separate the options and the parameter with spaces, or
+ with = or :. Comments can be used within the file. If the first letter on a
+ line is a '#'-symbol the rest of the line is treated as a comment.
+
+ If you want the parameter to contain spaces, you must enclose the entire
+ parameter within double quotes ("). Within those quotes, you specify a
+ quote as \".
+
+ NOTE: You must specify options and their arguments on the same line.
+
+ Example, set default time out and proxy in a config file:
+
+ # We want a 30 minute timeout:
+ -m 1800
+ # ... and we use a proxy for all accesses:
+ proxy = proxy.our.domain.com:8080
+
+ White spaces ARE significant at the end of lines, but all white spaces
+ leading up to the first characters of each line are ignored.
+
+ Prevent curl from reading the default file by using -q as the first command
+ line parameter, like:
+
+ curl -q www.thatsite.com
+
+ Force curl to get and display a local help page in case it is invoked
+ without URL by making a config file similar to:
+
+ # default url to get
+ url = "http://help.with.curl.com/curlhelp.html"
+
+ You can specify another config file to be read by using the -K/--config
+ flag. If you set config file name to "-" it'll read the config from stdin,
+ which can be handy if you want to hide options from being visible in process
+ tables etc:
+
+ echo "user = user:passwd" | curl -K - http://that.secret.site.com
+
+EXTRA HEADERS
+
+ When using curl in your own very special programs, you may end up needing
+ to pass on your own custom headers when getting a web page. You can do
+ this by using the -H flag.
+
+ Example, send the header "X-you-and-me: yes" to the server when getting a
+ page:
+
+ curl -H "X-you-and-me: yes" www.love.com
+
+ This can also be useful in case you want curl to send a different text in a
+ header than it normally does. The -H header you specify then replaces the
+ header curl would normally send. If you replace an internal header with an
+ empty one, you prevent that header from being sent. To prevent the Host:
+ header from being used:
+
+ curl -H "Host:" www.server.com
+
+FTP and PATH NAMES
+
+ Do note that when getting files with the ftp:// URL, the given path is
+ relative the directory you enter. To get the file 'README' from your home
+ directory at your ftp site, do:
+
+ curl ftp://user:passwd@my.site.com/README
+
+ But if you want the README file from the root directory of that very same
+ site, you need to specify the absolute file name:
+
+ curl ftp://user:passwd@my.site.com//README
+
+ (I.e with an extra slash in front of the file name.)
+
+SFTP and SCP and PATH NAMES
+
+ With sftp: and scp: URLs, the path name given is the absolute name on the
+ server. To access a file relative to the remote user's home directory,
+ prefix the file with /~/ , such as:
+
+ curl -u $USER sftp://home.example.com/~/.bashrc
+
+FTP and firewalls
+
+ The FTP protocol requires one of the involved parties to open a second
+ connection as soon as data is about to get transferred. There are two ways to
+ do this.
+
+ The default way for curl is to issue the PASV command which causes the
+ server to open another port and await another connection performed by the
+ client. This is good if the client is behind a firewall that doesn't allow
+ incoming connections.
+
+ curl ftp.download.com
+
+ If the server, for example, is behind a firewall that doesn't allow connections
+ on ports other than 21 (or if it just doesn't support the PASV command), the
+ other way to do it is to use the PORT command and instruct the server to
+ connect to the client on the given IP number and port (as parameters to the
+ PORT command).
+
+ The -P flag to curl supports a few different options. Your machine may have
+ several IP-addresses and/or network interfaces and curl allows you to select
+ which of them to use. Default address can also be used:
+
+ curl -P - ftp.download.com
+
+ Download with PORT but use the IP address of our 'le0' interface (this does
+ not work on windows):
+
+ curl -P le0 ftp.download.com
+
+ Download with PORT but use 192.168.0.10 as our IP address to use:
+
+ curl -P 192.168.0.10 ftp.download.com
+
+NETWORK INTERFACE
+
+ Get a web page from a server using a specified port for the interface:
+
+ curl --interface eth0:1 http://www.netscape.com/
+
+ or
+
+ curl --interface 192.168.1.10 http://www.netscape.com/
+
+HTTPS
+
+ Secure HTTP requires SSL libraries to be installed and used when curl is
+ built. If that is done, curl is capable of retrieving and posting documents
+ using the HTTPS protocol.
+
+ Example:
+
+ curl https://www.secure-site.com
+
+ Curl is also capable of using your personal certificates to get/post files
+ from sites that require valid certificates. The only drawback is that the
+ certificate needs to be in PEM-format. PEM is a standard and open format to
+ store certificates with, but it is not used by the most commonly used
+ browsers (Netscape and MSIE both use the so called PKCS#12 format). If you
+ want curl to use the certificates you use with your (favourite) browser, you
+ may need to download/compile a converter that can convert your browser's
+ formatted certificates to PEM formatted ones. This kind of converter is
+ included in recent versions of OpenSSL, and for older versions Dr Stephen
+ N. Henson has written a patch for SSLeay that adds this functionality. You
+ can get his patch (that requires an SSLeay installation) from his site at:
+ http://www.drh-consultancy.demon.co.uk/
+
+ Example on how to automatically retrieve a document using a certificate with
+ a personal password:
+
+ curl -E /path/to/cert.pem:password https://secure.site.com/
+
+ If you neglect to specify the password on the command line, you will be
+ prompted for the correct password before any data can be received.
+
+ Many older SSL-servers have problems with SSLv3 or TLS, which newer versions
+ of OpenSSL etc use, therefore it is sometimes useful to specify what
+ SSL-version curl should use. Use -3, -2 or -1 to specify that exact SSL
+ version to use (for SSLv3, SSLv2 or TLSv1 respectively):
+
+ curl -2 https://secure.site.com/
+
+ Otherwise, curl will first attempt to use v3 and then v2.
+
+ To use OpenSSL to convert your favourite browser's certificate into a PEM
+ formatted one that curl can use, do something like this:
+
+ In Netscape, you start with hitting the 'Security' menu button.
+
+ Select 'certificates->yours' and then pick a certificate in the list
+
+ Press the 'Export' button
+
+ enter your PIN code for the certs
+
+ select a proper place to save it
+
+ Run the 'openssl' application to convert the certificate. If you cd to the
+ openssl installation, you can do it like:
+
+ # ./apps/openssl pkcs12 -in [file you saved] -clcerts -out [PEMfile]
+
+ In Firefox, select Options, then Advanced, then the Encryption tab,
+ View Certificates. This opens the Certificate Manager, where you can
+ Export. Be sure to select PEM for the Save as type.
+
+ In Internet Explorer, select Internet Options, then the Content tab, then
+ Certificates. Then you can Export, and depending on the format you may
+ need to convert to PEM.
+
+ In Chrome, select Settings, then Show Advanced Settings. Under HTTPS/SSL
+ select Manage Certificates.
+
+RESUMING FILE TRANSFERS
+
+ To continue a file transfer where it was previously aborted, curl supports
+ resume on HTTP(S) downloads as well as FTP uploads and downloads.
+
+ Continue downloading a document:
+
+ curl -C - -o file ftp://ftp.server.com/path/file
+
+ Continue uploading a document(*1):
+
+ curl -C - -T file ftp://ftp.server.com/path/file
+
+ Continue downloading a document from a web server(*2):
+
+ curl -C - -o file http://www.server.com/
+
+ (*1) = This requires that the FTP server supports the non-standard command
+ SIZE. If it doesn't, curl will say so.
+
+ (*2) = This requires that the web server supports at least HTTP/1.1. If it
+ doesn't, curl will say so.
+
+TIME CONDITIONS
+
+ HTTP allows a client to specify a time condition for the document it
+ requests. It is If-Modified-Since or If-Unmodified-Since. Curl allows you to
+ specify them with the -z/--time-cond flag.
+
+ For example, you can easily make a download that only gets performed if the
+ remote file is newer than a local copy. It would be made like:
+
+ curl -z local.html http://remote.server.com/remote.html
+
+ Or you can download a file only if the local file is newer than the remote
+ one. Do this by prepending the date string with a '-', as in:
+
+ curl -z -local.html http://remote.server.com/remote.html
+
+ You can specify a "free text" date as condition. Tell curl to only download
+ the file if it was updated since January 12, 2012:
+
+ curl -z "Jan 12 2012" http://remote.server.com/remote.html
+
+ Curl will then accept a wide range of date formats. You always make the date
+ check the other way around by prepending it with a dash '-'.
+
+DICT
+
+ For fun try
+
+ curl dict://dict.org/m:curl
+ curl dict://dict.org/d:heisenbug:jargon
+ curl dict://dict.org/d:daniel:web1913
+
+ Aliases for 'm' are 'match' and 'find', and aliases for 'd' are 'define'
+ and 'lookup'. For example,
+
+ curl dict://dict.org/find:curl
+
+ Commands that break the URL description of the RFC (but not the DICT
+ protocol) are
+
+ curl dict://dict.org/show:db
+ curl dict://dict.org/show:strat
+
+ Authentication is still missing (but this is not required by the RFC)
+
+LDAP
+
+ If you have installed the OpenLDAP library, curl can take advantage of it
+ and offer ldap:// support.
+
+ LDAP is a complex thing and writing an LDAP query is not an easy task. I do
+ advise you to dig up the syntax description for that elsewhere. Two places
+ that might suit you are:
+
+ Netscape's "Netscape Directory SDK 3.0 for C Programmer's Guide Chapter 10:
+ Working with LDAP URLs":
+ http://developer.netscape.com/docs/manuals/dirsdk/csdk30/url.htm
+
+ RFC 2255, "The LDAP URL Format" http://curl.haxx.se/rfc/rfc2255.txt
+
+ To show you an example, this is how I can get all people from my local LDAP
+ server that has a certain sub-domain in their email address:
+
+ curl -B "ldap://ldap.frontec.se/o=frontec??sub?mail=*sth.frontec.se"
+
+ If I want the same info in HTML format, I can get it by not using the -B
+ (enforce ASCII) flag.
+
+ENVIRONMENT VARIABLES
+
+ Curl reads and understands the following environment variables:
+
+ http_proxy, HTTPS_PROXY, FTP_PROXY
+
+ They should be set for protocol-specific proxies. General proxy should be
+ set with
+
+ ALL_PROXY
+
+ A comma-separated list of host names that shouldn't go through any proxy is
+ set in (only an asterisk, '*' matches all hosts)
+
+ NO_PROXY
+
+ If the host name matches one of these strings, or the host is within the
+ domain of one of these strings, transactions with that node will not be
+ proxied.
+
+
+ The usage of the -x/--proxy flag overrides the environment variables.
+
+NETRC
+
+ Unix introduced the .netrc concept a long time ago. It is a way for a user
+ to specify name and password for commonly visited FTP sites in a file so
+ that you don't have to type them in each time you visit those sites. You
+ realize this is a big security risk if someone else gets hold of your
+ passwords, so therefore most unix programs won't read this file unless it is
+ only readable by yourself (curl doesn't care though).
+
+ Curl supports .netrc files if told to (using the -n/--netrc and
+ --netrc-optional options). This is not restricted to just FTP,
+ so curl can use it for all protocols where authentication is used.
+
+ A very simple .netrc file could look something like:
+
+ machine curl.haxx.se login iamdaniel password mysecret
+
+CUSTOM OUTPUT
+
+ To better allow script programmers to get to know about the progress of
+ curl, the -w/--write-out option was introduced. Using this, you can specify
+ what information from the previous transfer you want to extract.
+
+ To display the amount of bytes downloaded together with some text and an
+ ending newline:
+
+ curl -w 'We downloaded %{size_download} bytes\n' www.download.com
+
+KERBEROS FTP TRANSFER
+
+ Curl supports kerberos4 and kerberos5/GSSAPI for FTP transfers. You need
+ the kerberos package installed and used at curl build time for it to be
+ available.
+
+ First, get the krb-ticket the normal way, like with the kinit/kauth tool.
+ Then use curl in way similar to:
+
+ curl --krb private ftp://krb4site.com -u username:fakepwd
+
+ There's no use for a password on the -u switch, but a blank one will make
+ curl ask for one and you already entered the real password to kinit/kauth.
+
+TELNET
+
+ The curl telnet support is basic and very easy to use. Curl passes all data
+ passed to it on stdin to the remote server. Connect to a remote telnet
+ server using a command line similar to:
+
+ curl telnet://remote.server.com
+
+ And enter the data to pass to the server on stdin. The result will be sent
+ to stdout or to the file you specify with -o.
+
+ You might want the -N/--no-buffer option to switch off the buffered output
+ for slow connections or similar.
+
+ Pass options to the telnet protocol negotiation, by using the -t option. To
+ tell the server we use a vt100 terminal, try something like:
+
+ curl -tTTYPE=vt100 telnet://remote.server.com
+
+ Other interesting options for it -t include:
+
+ - XDISPLOC=<X display> Sets the X display location.
+
+ - NEW_ENV=<var,val> Sets an environment variable.
+
+ NOTE: The telnet protocol does not specify any way to login with a specified
+ user and password so curl can't do that automatically. To do that, you need
+ to track when the login prompt is received and send the username and
+ password accordingly.
+
+PERSISTENT CONNECTIONS
+
+ Specifying multiple files on a single command line will make curl transfer
+ all of them, one after the other in the specified order.
+
+ libcurl will attempt to use persistent connections for the transfers so that
+ the second transfer to the same host can use the same connection that was
+ already initiated and was left open in the previous transfer. This greatly
+ decreases connection time for all but the first transfer and it makes a far
+ better use of the network.
+
+ Note that curl cannot use persistent connections for transfers that are used
+ in subsequence curl invokes. Try to stuff as many URLs as possible on the
+ same command line if they are using the same host, as that'll make the
+ transfers faster. If you use an HTTP proxy for file transfers, practically
+ all transfers will be persistent.
+
+MULTIPLE TRANSFERS WITH A SINGLE COMMAND LINE
+
+ As is mentioned above, you can download multiple files with one command line
+ by simply adding more URLs. If you want those to get saved to a local file
+ instead of just printed to stdout, you need to add one save option for each
+ URL you specify. Note that this also goes for the -O option (but not
+ --remote-name-all).
+
+ For example: get two files and use -O for the first and a custom file
+ name for the second:
+
+ curl -O http://url.com/file.txt ftp://ftp.com/moo.exe -o moo.jpg
+
+ You can also upload multiple files in a similar fashion:
+
+ curl -T local1 ftp://ftp.com/moo.exe -T local2 ftp://ftp.com/moo2.txt
+
+IPv6
+
+ curl will connect to a server with IPv6 when a host lookup returns an IPv6
+ address and fall back to IPv4 if the connection fails. The --ipv4 and --ipv6
+ options can specify which address to use when both are available. IPv6
+ addresses can also be specified directly in URLs using the syntax:
+
+ http://[2001:1890:1112:1::20]/overview.html
+
+ When this style is used, the -g option must be given to stop curl from
+ interpreting the square brackets as special globbing characters. Link local
+ and site local addresses including a scope identifier, such as fe80::1234%1,
+ may also be used, but the scope portion must be numeric and the percent
+ character must be URL escaped. The previous example in an SFTP URL might
+ look like:
+
+ sftp://[fe80::1234%251]/
+
+ IPv6 addresses provided other than in URLs (e.g. to the --proxy, --interface
+ or --ftp-port options) should not be URL encoded.
+
+METALINK
+
+ Curl supports Metalink (both version 3 and 4 (RFC 5854) are supported), a way
+ to list multiple URIs and hashes for a file. Curl will make use of the mirrors
+ listed within for failover if there are errors (such as the file or server not
+ being available). It will also verify the hash of the file after the download
+ completes. The Metalink file itself is downloaded and processed in memory and
+ not stored in the local file system.
+
+ Example to use a remote Metalink file:
+
+ curl --metalink http://www.example.com/example.metalink
+
+ To use a Metalink file in the local file system, use FILE protocol (file://):
+
+ curl --metalink file://example.metalink
+
+ Please note that if FILE protocol is disabled, there is no way to use a local
+ Metalink file at the time of this writing. Also note that if --metalink and
+ --include are used together, --include will be ignored. This is because including
+ headers in the response will break Metalink parser and if the headers are included
+ in the file described in Metalink file, hash check will fail.
+
+MAILING LISTS
+
+ For your convenience, we have several open mailing lists to discuss curl,
+ its development and things relevant to this. Get all info at
+ http://curl.haxx.se/mail/. Some of the lists available are:
+
+ curl-users
+
+ Users of the command line tool. How to use it, what doesn't work, new
+ features, related tools, questions, news, installations, compilations,
+ running, porting etc.
+
+ curl-library
+
+ Developers using or developing libcurl. Bugs, extensions, improvements.
+
+ curl-announce
+
+ Low-traffic. Only receives announcements of new public versions. At worst,
+ that makes something like one or two mails per month, but usually only one
+ mail every second month.
+
+ curl-and-php
+
+ Using the curl functions in PHP. Everything curl with a PHP angle. Or PHP
+ with a curl angle.
+
+ curl-and-python
+
+ Python hackers using curl with or without the python binding pycurl.
+
+ Please direct curl questions, feature requests and trouble reports to one of
+ these mailing lists instead of mailing any individual.
diff --git a/libs/libcurl/docs/Makefile.am b/libs/libcurl/docs/Makefile.am
new file mode 100644
index 0000000000..8466a6c296
--- /dev/null
+++ b/libs/libcurl/docs/Makefile.am
@@ -0,0 +1,61 @@
+#***************************************************************************
+# _ _ ____ _
+# 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.
+#
+###########################################################################
+
+AUTOMAKE_OPTIONS = foreign no-dependencies
+
+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
+
+HTMLPAGES = $(GENHTMLPAGES) index.html
+
+SUBDIRS = examples libcurl
+
+CLEANFILES = $(GENHTMLPAGES) $(PDFPAGES)
+
+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 LIBCURL-STRUCTS
+
+MAN2HTML= roffit < $< >$@
+
+SUFFIXES = .1 .html .pdf
+
+html: $(HTMLPAGES)
+ cd libcurl; make html
+
+pdf: $(PDFPAGES)
+ cd libcurl; make pdf
+
+.1.html:
+ $(MAN2HTML)
+
+.1.pdf:
+ @(foo=`echo $@ | sed -e 's/\.[0-9]$$//g'`; \
+ groff -Tps -man $< >$$foo.ps; \
+ ps2pdf $$foo.ps $@; \
+ rm $$foo.ps; \
+ echo "converted $< to $@")
+
diff --git a/libs/libcurl/docs/Makefile.in b/libs/libcurl/docs/Makefile.in
new file mode 100644
index 0000000000..971c63f1db
--- /dev/null
+++ b/libs/libcurl/docs/Makefile.in
@@ -0,0 +1,819 @@
+# Makefile.in generated by automake 1.14 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+#***************************************************************************
+# _ _ ____ _
+# 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.
+#
+###########################################################################
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = docs
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/mkinstalldirs INSTALL THANKS TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/curl-compilers.m4 \
+ $(top_srcdir)/m4/curl-confopts.m4 \
+ $(top_srcdir)/m4/curl-functions.m4 \
+ $(top_srcdir)/m4/curl-openssl.m4 \
+ $(top_srcdir)/m4/curl-override.m4 \
+ $(top_srcdir)/m4/curl-reentrant.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/xc-am-iface.m4 \
+ $(top_srcdir)/m4/xc-cc-check.m4 \
+ $(top_srcdir)/m4/xc-lt-iface.m4 \
+ $(top_srcdir)/m4/xc-translit.m4 \
+ $(top_srcdir)/m4/xc-val-flgs.m4 \
+ $(top_srcdir)/m4/zz40-xc-ovr.m4 \
+ $(top_srcdir)/m4/zz50-xc-ovr.m4 \
+ $(top_srcdir)/m4/zz60-xc-ovr.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/lib/curl_config.h \
+ $(top_builddir)/include/curl/curlbuild.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+depcomp =
+am__depfiles_maybe =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+MANS = $(man_MANS)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BLANK_AT_MAKETIME = @BLANK_AT_MAKETIME@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CFLAG_CURL_SYMBOL_HIDING = @CFLAG_CURL_SYMBOL_HIDING@
+CONFIGURE_OPTIONS = @CONFIGURE_OPTIONS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAG_CURL_STATICLIB = @CPPFLAG_CURL_STATICLIB@
+CURLVERSION = @CURLVERSION@
+CURL_CA_BUNDLE = @CURL_CA_BUNDLE@
+CURL_CFLAG_EXTRAS = @CURL_CFLAG_EXTRAS@
+CURL_DISABLE_DICT = @CURL_DISABLE_DICT@
+CURL_DISABLE_FILE = @CURL_DISABLE_FILE@
+CURL_DISABLE_FTP = @CURL_DISABLE_FTP@
+CURL_DISABLE_GOPHER = @CURL_DISABLE_GOPHER@
+CURL_DISABLE_HTTP = @CURL_DISABLE_HTTP@
+CURL_DISABLE_IMAP = @CURL_DISABLE_IMAP@
+CURL_DISABLE_LDAP = @CURL_DISABLE_LDAP@
+CURL_DISABLE_LDAPS = @CURL_DISABLE_LDAPS@
+CURL_DISABLE_POP3 = @CURL_DISABLE_POP3@
+CURL_DISABLE_PROXY = @CURL_DISABLE_PROXY@
+CURL_DISABLE_RTSP = @CURL_DISABLE_RTSP@
+CURL_DISABLE_SMTP = @CURL_DISABLE_SMTP@
+CURL_DISABLE_TELNET = @CURL_DISABLE_TELNET@
+CURL_DISABLE_TFTP = @CURL_DISABLE_TFTP@
+CURL_LT_SHLIB_VERSIONED_FLAVOUR = @CURL_LT_SHLIB_VERSIONED_FLAVOUR@
+CURL_NETWORK_AND_TIME_LIBS = @CURL_NETWORK_AND_TIME_LIBS@
+CURL_NETWORK_LIBS = @CURL_NETWORK_LIBS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+ENABLE_SHARED = @ENABLE_SHARED@
+ENABLE_STATIC = @ENABLE_STATIC@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GREP = @GREP@
+HAVE_GNUTLS_SRP = @HAVE_GNUTLS_SRP@
+HAVE_LDAP_SSL = @HAVE_LDAP_SSL@
+HAVE_LIBZ = @HAVE_LIBZ@
+HAVE_NSS_INITCONTEXT = @HAVE_NSS_INITCONTEXT@
+HAVE_SSLEAY_SRP = @HAVE_SSLEAY_SRP@
+IDN_ENABLED = @IDN_ENABLED@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+IPV6_ENABLED = @IPV6_ENABLED@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBCURL_LIBS = @LIBCURL_LIBS@
+LIBMETALINK_CPPFLAGS = @LIBMETALINK_CPPFLAGS@
+LIBMETALINK_LDFLAGS = @LIBMETALINK_LDFLAGS@
+LIBMETALINK_LIBS = @LIBMETALINK_LIBS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MANOPT = @MANOPT@
+MKDIR_P = @MKDIR_P@
+NM = @NM@
+NMEDIT = @NMEDIT@
+NROFF = @NROFF@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PKGADD_NAME = @PKGADD_NAME@
+PKGADD_PKG = @PKGADD_PKG@
+PKGADD_VENDOR = @PKGADD_VENDOR@
+PKGCONFIG = @PKGCONFIG@
+RANDOM_FILE = @RANDOM_FILE@
+RANLIB = @RANLIB@
+REQUIRE_LIB_DEPS = @REQUIRE_LIB_DEPS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SSL_ENABLED = @SSL_ENABLED@
+STRIP = @STRIP@
+SUPPORT_FEATURES = @SUPPORT_FEATURES@
+SUPPORT_PROTOCOLS = @SUPPORT_PROTOCOLS@
+USE_ARES = @USE_ARES@
+USE_AXTLS = @USE_AXTLS@
+USE_CYASSL = @USE_CYASSL@
+USE_DARWINSSL = @USE_DARWINSSL@
+USE_GNUTLS = @USE_GNUTLS@
+USE_GNUTLS_NETTLE = @USE_GNUTLS_NETTLE@
+USE_LIBRTMP = @USE_LIBRTMP@
+USE_LIBSSH2 = @USE_LIBSSH2@
+USE_NGHTTP2 = @USE_NGHTTP2@
+USE_NSS = @USE_NSS@
+USE_OPENLDAP = @USE_OPENLDAP@
+USE_POLARSSL = @USE_POLARSSL@
+USE_SCHANNEL = @USE_SCHANNEL@
+USE_SSLEAY = @USE_SSLEAY@
+USE_WINDOWS_SSPI = @USE_WINDOWS_SSPI@
+VERSION = @VERSION@
+VERSIONNUM = @VERSIONNUM@
+ZLIB_LIBS = @ZLIB_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+libext = @libext@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AUTOMAKE_OPTIONS = foreign no-dependencies
+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
+HTMLPAGES = $(GENHTMLPAGES) index.html
+SUBDIRS = examples libcurl
+CLEANFILES = $(GENHTMLPAGES) $(PDFPAGES)
+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 LIBCURL-STRUCTS
+
+MAN2HTML = roffit < $< >$@
+SUFFIXES = .1 .html .pdf
+all: all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .1 .html .pdf
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign docs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile $(MANS)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am uninstall-man uninstall-man1
+
+
+html: $(HTMLPAGES)
+ cd libcurl; make html
+
+pdf: $(PDFPAGES)
+ cd libcurl; make pdf
+
+.1.html:
+ $(MAN2HTML)
+
+.1.pdf:
+ @(foo=`echo $@ | sed -e 's/\.[0-9]$$//g'`; \
+ groff -Tps -man $< >$$foo.ps; \
+ ps2pdf $$foo.ps $@; \
+ rm $$foo.ps; \
+ echo "converted $< to $@")
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libs/libcurl/docs/README b/libs/libcurl/docs/README
new file mode 100644
index 0000000000..2ffacc32cc
--- /dev/null
+++ b/libs/libcurl/docs/README
@@ -0,0 +1,49 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+README
+
+ Curl is a command line tool for transferring data specified with URL
+ syntax. Find out how to use curl by reading the curl.1 man page or the
+ MANUAL document. Find out how to install Curl by reading the INSTALL
+ document.
+
+ libcurl is the library curl is using to do its job. It is readily
+ available to be used by your software. Read the libcurl.3 man page to
+ learn how!
+
+ You find answers to the most frequent questions we get in the FAQ document.
+
+ Study the COPYING file for distribution terms and similar. If you distribute
+ curl binaries or other binaries that involve libcurl, you might enjoy the
+ LICENSE-MIXING document.
+
+CONTACT
+
+ If you have problems, questions, ideas or suggestions, please contact us
+ by posting to a suitable mailing list. See http://curl.haxx.se/mail/
+
+ All contributors to the project are listed in the THANKS document.
+
+WEB SITE
+
+ Visit the curl web site for the latest news and downloads:
+
+ http://curl.haxx.se/
+
+GIT
+
+ To download the very latest source off the GIT server do this:
+
+ git clone git://github.com/bagder/curl.git
+
+ (you'll get a directory named curl created, filled with the source code)
+
+NOTICE
+
+ Curl contains pieces of source code that is Copyright (c) 1998, 1999
+ Kungliga Tekniska Hgskolan. This notice is included here to comply with the
+ distribution terms.
diff --git a/libs/libcurl/docs/README.netware b/libs/libcurl/docs/README.netware
new file mode 100644
index 0000000000..41da2e8dc0
--- /dev/null
+++ b/libs/libcurl/docs/README.netware
@@ -0,0 +1,27 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+README.netware
+
+ Read the README file first.
+
+ Curl has been successfully compiled with gcc / nlmconv on different flavours
+ of Linux as well as with the official Metrowerks CodeWarrior compiler.
+ While not being the main development target, a continously growing share of
+ curl users are NetWare-based, specially also consuming the lib from PHP.
+
+ The unix-style man pages are tricky to read on windows, so therefore are all
+ those pages converted to HTML as well as pdf, and included in the release
+ archives.
+
+ The main curl.1 man page is also "built-in" in the command line tool. Use a
+ command line similar to this in order to extract a separate text file:
+
+ curl -M >manual.txt
+
+ Read the INSTALL file for instructions how to compile curl self.
+
+
diff --git a/libs/libcurl/docs/README.win32 b/libs/libcurl/docs/README.win32
new file mode 100644
index 0000000000..cfd45dd25b
--- /dev/null
+++ b/libs/libcurl/docs/README.win32
@@ -0,0 +1,26 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+README.win32
+
+ Read the README file first.
+
+ Curl has been compiled, built and run on all sorts of Windows and win32
+ systems. While not being the main develop target, a fair share of curl users
+ are win32-based.
+
+ The unix-style man pages are tricky to read on windows, so therefore are all
+ those pages converted to HTML as well as pdf, and included in the release
+ archives.
+
+ The main curl.1 man page is also "built-in" in the command line tool. Use a
+ command line similar to this in order to extract a separate text file:
+
+ curl -M >manual.txt
+
+ Read the INSTALL file for instructions how to compile curl self.
+
+
diff --git a/libs/libcurl/docs/RELEASE-NOTES b/libs/libcurl/docs/RELEASE-NOTES
new file mode 100644
index 0000000000..b8f1719bab
--- /dev/null
+++ b/libs/libcurl/docs/RELEASE-NOTES
@@ -0,0 +1,111 @@
+Curl and libcurl 7.33.0
+
+ Public curl releases: 135
+ Command line options: 161
+ curl_easy_setopt() options: 205
+ Public functions in libcurl: 58
+ Known libcurl bindings: 42
+ Contributors: 1057
+
+This release includes the following changes:
+
+ 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 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:
+
+ o see docs/KNOWN_BUGS (http://curl.haxx.se/docs/knownbugs.html)
+
+This release would not have looked like this without help, code, reports and
+advice from friends like these:
+
+ 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/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
diff --git a/libs/libcurl/docs/RESOURCES b/libs/libcurl/docs/RESOURCES
new file mode 100644
index 0000000000..760e75975a
--- /dev/null
+++ b/libs/libcurl/docs/RESOURCES
@@ -0,0 +1,83 @@
+ _ _ ____ _
+ Project ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+
+This document lists documents and standards used by curl.
+
+ RFC 959 - The FTP protocol
+
+ RFC 1635 - How to Use Anonymous FTP
+
+ RFC 1738 - Uniform Resource Locators
+
+ RFC 1777 - defines the LDAP protocol
+
+ RFC 1808 - Relative Uniform Resource Locators
+
+ RFC 1867 - Form-based File Upload in HTML
+
+ RFC 1950 - ZLIB Compressed Data Format Specification
+
+ RFC 1951 - DEFLATE Compressed Data Format Specification
+
+ RFC 1952 - gzip compression format
+
+ RFC 1959 - LDAP URL syntax
+
+ RFC 2045-2049 - Everything you need to know about MIME! (needed for form
+ based upload)
+
+ RFC 2068 - HTTP 1.1 (obsoleted by RFC 2616)
+
+ RFC 2104 - Keyed-Hashing for Message Authentication
+
+ RFC 2109 - HTTP State Management Mechanism (cookie stuff)
+ - Also, read Netscape's specification at
+ http://curl.haxx.se/rfc/cookie_spec.html
+
+ RFC 2183 - The Content-Disposition Header Field
+
+ RFC 2195 - CRAM-MD5 authentication
+
+ RFC 2229 - A Dictionary Server Protocol
+
+ RFC 2255 - Newer LDAP URL syntax document.
+
+ RFC 2231 - MIME Parameter Value and Encoded Word Extensions:
+ Character Sets, Languages, and Continuations
+
+ RFC 2388 - "Returning Values from Forms: multipart/form-data"
+ Use this as an addition to the RFC1867
+
+ RFC 2396 - "Uniform Resource Identifiers: Generic Syntax and Semantics" This
+ one obsoletes RFC 1738, but since RFC 1738 is often mentioned
+ I've left it in this list.
+
+ RFC 2428 - FTP Extensions for IPv6 and NATs
+
+ RFC 2577 - FTP Security Considerations
+
+ RFC 2616 - HTTP 1.1, the latest
+
+ RFC 2617 - HTTP Authentication
+
+ RFC 2718 - Guidelines for new URL Schemes
+
+ RFC 2732 - Format for Literal IPv6 Addresses in URL's
+
+ RFC 2818 - HTTP Over TLS (TLS is the successor to SSL)
+
+ RFC 2821 - SMTP protocol
+
+ RFC 2964 - Use of HTTP State Management
+
+ RFC 2965 - HTTP State Management Mechanism. Cookies. Obsoletes RFC2109
+
+ RFC 3207 - SMTP over TLS
+
+ RFC 4616 - PLAIN authentication
+
+ RFC 4954 - SMTP Authentication
diff --git a/libs/libcurl/docs/SSLCERTS b/libs/libcurl/docs/SSLCERTS
new file mode 100644
index 0000000000..e6b05c3e3f
--- /dev/null
+++ b/libs/libcurl/docs/SSLCERTS
@@ -0,0 +1,138 @@
+ Peer SSL Certificate Verification
+ =================================
+
+(NOTE: If libcurl was built with Schannel or Secure Transport support, then
+this does not apply to you. Scroll down for details on how the OS-native
+engines handle SSL certificates. If you're not sure, then run "curl -V" and
+read the results. If the version string says "WinSSL" in it, then it was built
+with Schannel support.)
+
+libcurl performs peer SSL certificate verification by default. This is done
+by using CA cert bundle that the SSL library can use to make sure the peer's
+server certificate is valid.
+
+If you communicate with HTTPS or FTPS servers using certificates that are
+signed by CAs present in the bundle, you can be sure that the remote server
+really is the one it claims to be.
+
+Until 7.18.0, curl bundled a severely outdated ca bundle file that was
+installed by default. These days, the curl archives include no ca certs at
+all. You need to get them elsewhere. See below for example.
+
+If the remote server uses a self-signed certificate, if you don't install a CA
+cert bundle, if the server uses a certificate signed by a CA that isn't
+included in the bundle you use or if the remote host is an impostor
+impersonating your favorite site, and you want to transfer files from this
+server, do one of the following:
+
+ 1. Tell libcurl to *not* verify the peer. With libcurl you disable this with
+ curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, FALSE);
+
+ With the curl command line tool, you disable this with -k/--insecure.
+
+ 2. Get a CA certificate that can verify the remote server and use the proper
+ option to point out this CA cert for verification when connecting. For
+ libcurl hackers: curl_easy_setopt(curl, CURLOPT_CAPATH, capath);
+
+ With the curl command line tool: --cacert [file]
+
+ 3. Add the CA cert for your server to the existing default CA cert bundle.
+ The default path of the CA bundle used can be changed by running configure
+ with the --with-ca-bundle option pointing out the path of your choice.
+
+ To do this, you need to get the CA cert for your server in PEM format and
+ then append that to your CA cert bundle.
+
+ If you use Internet Explorer, this is one way to get extract the CA cert
+ for a particular server:
+
+ o View the certificate by double-clicking the padlock
+ o Find out where the CA certificate is kept (Certificate>
+ Authority Information Access>URL)
+ o Get a copy of the crt file using curl
+ o Convert it from crt to PEM using the openssl tool:
+ openssl x509 -inform DES -in yourdownloaded.crt \
+ -out outcert.pem -text
+ o Append the 'outcert.pem' to the CA cert bundle or use it stand-alone
+ as described below.
+
+ If you use the 'openssl' tool, this is one way to get extract the CA cert
+ for a particular server:
+
+ o openssl s_client -connect xxxxx.com:443 |tee logfile
+ o type "QUIT", followed by the "ENTER" key
+ o The certificate will have "BEGIN CERTIFICATE" and "END CERTIFICATE"
+ markers.
+ o If you want to see the data in the certificate, you can do: "openssl
+ x509 -inform PEM -in certfile -text -out certdata" where certfile is
+ the cert you extracted from logfile. Look in certdata.
+ o If you want to trust the certificate, you can append it to your
+ cert_bundle or use it stand-alone as described. Just remember that the
+ security is no better than the way you obtained the certificate.
+
+ 4. If you're using the curl command line tool, you can specify your own CA
+ cert path by setting the environment variable CURL_CA_BUNDLE to the path
+ of your choice.
+
+ If you're using the curl command line tool on Windows, curl will search
+ for a CA cert file named "curl-ca-bundle.crt" in these directories and in
+ this order:
+ 1. application's directory
+ 2. current working directory
+ 3. Windows System directory (e.g. C:\windows\system32)
+ 4. Windows Directory (e.g. C:\windows)
+ 5. all directories along %PATH%
+
+ 5. Get a better/different/newer CA cert bundle! One option is to extract the
+ one a recent Firefox browser uses by running 'make ca-bundle' in the curl
+ build tree root, or possibly download a version that was generated this
+ way for you:
+
+ http://curl.haxx.se/docs/caextract.html
+
+Neglecting to use one of the above methods when dealing with a server using a
+certificate that isn't signed by one of the certificates in the installed CA
+cert bundle, will cause SSL to report an error ("certificate verify failed")
+during the handshake and SSL will then refuse further communication with that
+server.
+
+ Peer SSL Certificate Verification with NSS
+ ==========================================
+
+If libcurl was built with NSS support, then depending on the OS distribution,
+it is probably required to take some additional steps to use the system-wide CA
+cert db. RedHat ships with an additional module, libnsspem.so, which enables
+NSS to read the OpenSSL PEM CA bundle. This library is missing in OpenSuSE, and
+without it, NSS can only work with its own internal formats. NSS also has a new
+database format: https://wiki.mozilla.org/NSS_Shared_DB
+
+Starting with version 7.19.7, libcurl will check for the NSS version it runs,
+and automatically add the 'sql:' prefix to the certdb directory (either the
+hardcoded default /etc/pki/nssdb or the directory configured with SSL_DIR
+environment variable) if version 3.12.0 or later is detected. To check which
+ertdb format your distribution provides, examine the default
+certdb location: /etc/pki/nssdb; the new certdb format can be identified by
+the filenames cert9.db, key4.db, pkcs11.txt; filenames of older versions are
+cert8.db, key3.db, modsec.db.
+
+Usually these cert databases are empty, but NSS also has built-in CAs which are
+provided through a shared library, libnssckbi.so; if you want to use these
+built-in CAs, then create a symlink to libnssckbi.so in /etc/pki/nssdb:
+ln -s /usr/lib[64]/libnssckbi.so /etc/pki/nssdb/libnssckbi.so
+
+ Peer SSL Certificate Verification with Schannel and Secure Transport
+ ====================================================================
+
+If libcurl was built with Schannel (Microsoft's TLS/SSL engine) or Secure
+Transport (Apple's TLS/SSL engine) support, then libcurl will still perform
+peer certificate verification, but instead of using a CA cert bundle, it will
+use the certificates that are built into the OS. These are the same
+certificates that appear in the Internet Options control panel (under Windows)
+or Keychain Access application (under OS X). Any custom security rules for
+certificates will be honored.
+
+Schannel will run CRL checks on certificates unless peer verification is
+disabled. Secure Transport on iOS will run OCSP checks on certificates unless
+peer verification is disabled. Secure Transport on OS X will run either OCSP
+or CRL checks on certificates if those features are enabled, and this behavior
+can be adjusted in the preferences of Keychain Access.
diff --git a/libs/libcurl/docs/THANKS b/libs/libcurl/docs/THANKS
new file mode 100644
index 0000000000..693139bf73
--- /dev/null
+++ b/libs/libcurl/docs/THANKS
@@ -0,0 +1,1063 @@
+ This project has been alive for many years. Countless people have provided
+ feedback that have improved curl. Here follows a list of people that have
+ contributed (a-z order).
+
+ If you have contributed but are missing here, please let us know!
+
+Aaron Oneal
+Aaron Orenstein
+Adam D. Moss
+Adam Light
+Adam Piggott
+Adam Tkac
+Adrian Schuur
+Adriano Meirelles
+Ajit Dhumale
+Aki Koskinen
+Akos Pasztory
+Alan Pinstein
+Albert Chin-A-Young
+Albert Choy
+Ale Vesely
+Alejandro Alvarez
+Aleksandar Milivojevic
+Aleksey Tulinov
+Alessandro Ghedini
+Alessandro Vesely
+Alex Bligh
+Alex Fishman
+Alex Gruz
+Alex Neblett
+Alex Suykov
+Alex Vinnik
+Alex aka WindEagle
+Alexander Beedie
+Alexander Klauer
+Alexander Kourakos
+Alexander Krasnostavsky
+Alexander Lazic
+Alexander Zhuravlev
+Alexey Borzov
+Alexey Pesternikov
+Alexey Simak
+Alexey Zakhlestin
+Alexis Carvalho
+Alfred Gebert
+Allen Pulsifer
+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
+Andreas Schuldei
+Andreas Wurf
+Andrei Benea
+Andrei Cipu
+Andres Garcia
+Andrew Benham
+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
+Andy Tsouladze
+Angus Mackay
+Anthony Bryan
+Anthony G. Basile
+Antoine Calando
+Anton Bychkov
+Anton Kalmykov
+Anton Malov
+Anton Yabchinskiy
+Arkadiusz Miskiewicz
+Armel Asselin
+Arnaud Compan
+Arnaud Ebalard
+Arthur Murray
+Arve Knudsen
+Ates Goral
+Augustus Saunders
+Avery Fay
+Axel Tillequin
+Balaji Parasuram
+Balint Szilakszi
+Bart Whiteley
+Bas Mevissen
+Ben Darnell
+Ben Greear
+Ben Madsen
+Ben Noordhuis
+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
+Björn Stenberg
+Blaise Potard
+Bob Relyea
+Bob Richmond
+Bob Schader
+Bogdan Nicula
+Brad Burdick
+Brad Hards
+Brad King
+Bradford Bruce
+Brandon Wang
+Brendan Jurd
+Brent Beardsley
+Brian Akins
+Brian Dessent
+Brian J. Murrell
+Brian R Duffy
+Brian Ulm
+Brock Noland
+Bruce Mitchener
+Bruno de Carvalho
+Bryan Henderson
+Bryan Kemp
+Byrial Jensen
+Cameron Kaiser
+Camille Moncelier
+Caolan McNamara
+Carsten Lange
+Casey O'Donnell
+Cedric Deltheil
+Chad Monroe
+Chandrakant Bagul
+Charles Kerr
+Chih-Chung Chang
+Chris "Bob Bob"
+Chris Combes
+Chris Conroy
+Chris Deidun
+Chris Flerackers
+Chris Gaukroger
+Chris Maltby
+Chris Mumford
+Chris Smowton
+Christian Grothoff
+Christian Hägele
+Christian Krause
+Christian Kurz
+Christian Robottom Reis
+Christian Schmitz
+Christian Vogt
+Christian Weisgerber
+Christophe Demory
+Christophe Legry
+Christopher Conroy
+Christopher Palow
+Christopher R. Palmer
+Christopher Stone
+Ciprian Badescu
+Claes Jakobsson
+Clarence Gardner
+Clemens Gruber
+Clifford Wolf
+Cody Jones
+Colin Hogben
+Colin Watson
+Colm Buckley
+Constantine Sapuntzakis
+Cory Nelson
+Craig A West
+Craig Davison
+Craig Markwardt
+Cris Bailiff
+Cristian Rodríguez
+Curt Bogmine
+Cyrill Osterwalder
+Cédric Deltheil
+Dag Ekengren
+Dagobert Michelsen
+Damien Adant
+Dan Becker
+Dan C
+Dan Fandrich
+Dan Locks
+Dan Nelson
+Dan Petitt
+Dan Torop
+Dan Zitter
+Daniel Black
+Daniel Cater
+Daniel Egger
+Daniel Johnson
+Daniel Mentz
+Daniel Steinberg
+Daniel Stenberg
+Daniel Theron
+Daniel at touchtunes
+Darryl House
+Darshan Mody
+Dave Dribin
+Dave Halbakken
+Dave Hamilton
+Dave May
+Dave Reisner
+Dave Vasilevsky
+David Bau
+David Binderman
+David Blaikie
+David Byron
+David Cohen
+David Eriksson
+David Houlder
+David Hull
+David J Meyer
+David James
+David Kierznowski
+David Kimdon
+David Lang
+David LeBlanc
+David McCreedy
+David Odin
+David Phillips
+David Rosenstrauch
+David Shaw
+David Strauss
+David Tarendash
+David Thiel
+David Wright
+David Yan
+Dengminwen
+Detlef Schmier
+Didier Brisebourg
+Diego Casorran
+Dima Barsky
+Dimitre Dimitrov
+Dimitris Sarris
+Dinar
+Dirk Eddelbuettel
+Dirk Manske
+Dmitri Shubin
+Dmitriy Sergeyev
+Dmitry Bartsevich
+Dmitry Kurochkin
+Dmitry Popov
+Dmitry Rechkin
+Dolbneff A.V
+Domenico Andreoli
+Dominick Meglio
+Dominique Leuenberger
+Doug Kaufman
+Doug Porter
+Douglas E. Wegscheid
+Douglas Kilpatrick
+Douglas R. Horner
+Douglas Steinwand
+Dov Murik
+Duane Cathey
+Duncan
+Duncan Mac-Vicar Prett
+Dustin Boswell
+Dylan Ellicott
+Dylan Salisbury
+Early Ehlinger
+Ebenezer Ikonne
+Edin Kadribasic
+Eduard Bloch
+Edward Rudd
+Edward Sheldrake
+Eelco Dolstra
+Eetu Ojanen
+Eldar Zaitov
+Ellis Pritchard
+Emanuele Bovisio
+Emil Romanus
+Emiliano Ida
+Enrico Scholz
+Enrik Berkhan
+Eric Cooper
+Eric Hu
+Eric Landes
+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
+Fabrizio Ammollo
+Fedor Karpelevitch
+Felix von Leitner
+Feng Tu
+Florian Schoppmann
+Forrest Cahoon
+Frank Hempel
+Frank Keeney
+Frank McGeough
+Frank Meier
+Frank Ticheler
+Frank Van Uffelen
+František Kučera
+Fred Machado
+Fred New
+Fred Noz
+Frederic Lepied
+Fredrik Thulin
+Gabriel Kuri
+Gabriel Sjoberg
+Garrett Holmstrom
+Gary Maxwell
+Gautam Kachroo
+Gautam Mani
+Gavrie Philipson
+Gaz Iqbal
+Georg Horn
+Georg Huettenegger
+Georg Lippitsch
+Georg Wicherski
+Gerd v. Egidy
+Gerhard Herre
+Gerrit Bruchhäuser
+Ghennadi Procopciuc
+Giancarlo Formicuccia
+Giaslas Georgios
+Gil Weber
+Gilad
+Gilbert Ramirez Jr.
+Gilles Blanc
+Gisle Vanem
+Giuseppe Attardi
+Giuseppe D'Ambrosio
+Glen Nakamura
+Glen Scott
+Gokhan Sengun
+Grant Erickson
+Greg Hewgill
+Greg Morse
+Greg Onufer
+Greg Zavertnik
+Grigory Entin
+Guenole Bescon
+Guenter Knauf
+Guido Berhoerster
+Guillaume Arluison
+Gustaf Hui
+Gwenole Beauchesne
+Götz Babin-Ebell
+Hamish Mackenzie
+Hang Kin Lau
+Hang Su
+Hanno Kranzhoff
+Hans Steegers
+Hans-Jurgen May
+Hardeep Singh
+Harshal Pradhan
+Hauke Duden
+Heikki Korpela
+Heinrich Ko
+Hendrik Visage
+Henrik Storner
+Henry Ludemann
+Herve Amblard
+Hidemoto Nakada
+Ho-chi Chen
+Hoi-Ho Chan
+Hongli Lai
+Howard Chu
+Hzhijun
+Ian D Allen
+Ian Ford
+Ian Gulliver
+Ian Lynagh
+Ian Turner
+Ian Wilkes
+Ignacio Vazquez-Abrams
+Igor Franchuk
+Igor Novoseltsev
+Igor Polyakov
+Ilguiz Latypov
+Ilja van Sprundel
+Immanuel Gregoire
+Ingmar Runge
+Ingo Ralf Blum
+Ingo Wilken
+Ishan SinghLevett
+Jack Zhang
+Jacky Lam
+Jacob Meuser
+Jacob Moshenko
+Jad Chamcham
+James Bursa
+James Cheng
+James Clancy
+James Cone
+James Gallagher
+James Griffiths
+James Housley
+James MacMillan
+Jamie Lokier
+Jamie Newton
+Jamie Wilkinson
+Jan Ehrhardt
+Jan Koen Annot
+Jan Kunder
+Jan Schaumann
+Jan Van Boghout
+Jared Jennings
+Jared Lundell
+Jari Sundell
+Jason Glasgow
+Jason Liu
+Jason McDonald
+Jason S. Priebe
+Jay Austin
+Jayesh A Shah
+Jaz Fresh
+Jean Jacques Drouin
+Jean-Claude Chauve
+Jean-Francois Bertrand
+Jean-Louis Lemaire
+Jean-Marc Ranger
+Jean-Noel Rouvignac
+Jean-Philippe Barrette-LaPierre
+Jeff Connelly
+Jeff Johnson
+Jeff Lawson
+Jeff Phillips
+Jeff Pohlmeyer
+Jeff Weber
+Jeffrey Pohlmeyer
+Jeremy Friesner
+Jeremy Huddleston
+Jerome Muffat-Meridol
+Jerome Vouillon
+Jerry Wu
+Jes Badwal
+Jesper Jensen
+Jesse Noller
+Jie He
+Jim Drash
+Jim Freeman
+Jim Hollinger
+Jim Meyering
+Jiri Hruska
+Jiri Jaburek
+Jocelyn Jaubert
+Joe Halpin
+Joe Malicki
+Joe Mason
+Joel Chen
+Jofell Gallardo
+Johan Anderson
+Johan Nilsson
+Johan van Selst
+Johannes Bauer
+John Bradshaw
+John Crow
+John Dennis
+John E. Malmberg
+John Gardiner Myers
+John Janssen
+John Joseph Bachir
+John Kelly
+John Lask
+John Lightsey
+John Marino
+John McGowan
+John P. McCaskey
+John Suprock
+John Wilkinson
+John-Mark Bell
+Johnny Luong
+Jon Grubbs
+Jon Nelson
+Jon Sargeant
+Jon Travis
+Jon Turner
+Jonas Forsman
+Jonas Schnelli
+Jonatan Lander
+Jonathan Hseu
+Jonathan Nieder
+Jongki Suwandi
+Jose Kahan
+Josef Wolf
+Josh Kapell
+Joshua Kwan
+Josue Andrade Gomes
+Juan Barreto
+Juan F. Codagnone
+Juan Ignacio Hervás
+Judson Bishop
+Juergen Wilke
+Jukka Pihl
+Julian Noble
+Julian Taylor
+Julien Chaffraix
+Julien Royer
+Jun-ichiro itojun Hagino
+Jurij Smakov
+Justin Fletcher
+Justin Karneges
+Jörg Mueller-Tolk
+Jörn Hartroth
+Kai Engert
+Kai Sommerfeld
+Kai-Uwe Rommel
+Kalle Vahlman
+Kamil Dudka
+Kang-Jin Lee
+Karl M
+Karl Moerder
+Karol Pietrzak
+Kaspar Brand
+Katie Wang
+Kees Cook
+Keith MacDonald
+Keith McGuigan
+Keith Mok
+Ken Hirsch
+Ken Rastatter
+Kenny To
+Kent Boortz
+Keshav Krity
+Kevin Baughman
+Kevin Fisk
+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
+Kristian Gunstone
+Kristian Köhntopp
+Kyle Sallee
+Lachlan O'Dea
+Larry Campbell
+Larry Fahnoe
+Lars Buitinck
+Lars Gustafsson
+Lars J. Aas
+Lars Johannesen
+Lars Nilsson
+Lars Torben Wilson
+Lau Hang Kin
+Laurent Rabret
+Legoff Vincent
+Lehel Bernadt
+Len Krause
+Lenaic Lefever
+Lenny Rachitsky
+Liam Healy
+Lijo Antony
+Linas Vepstas
+Ling Thio
+Linus Nielsen Feltzing
+Lisa Xu
+Liza Alenchery
+Lluís Batlle i Rossell
+Loic Dachary
+Loren Kirkby
+Luca Altea
+Luca Alteas
+Lucas Adamski
+Ludovico Cavedon
+Lukasz Czekierda
+Luke Amery
+Luke Call
+Luong Dinh Dung
+Maciej Karpiuk
+Maciej W. Rozycki
+Mamoru Tasaka
+Mandy Wu
+Manfred Schwarb
+Manuel Massing
+Marc Boucher
+Marc Doughty
+Marc Hoersken
+Marc Kleine-Budde
+Marcel Raad
+Marcel Roelofs
+Marcelo Juchem
+Marcin Adamski
+Marcin Konicki
+Marco G. Salvagno
+Marco Maggi
+Marcus Sundberg
+Marcus Webster
+Mario Schroeder
+Mark Brand
+Mark Butler
+Mark Davies
+Mark Eichin
+Mark Incley
+Mark Karpeles
+Mark Lentczner
+Mark Salisbury
+Mark Snelling
+Mark Tully
+Markus Duft
+Markus Koetter
+Markus Moeller
+Markus Oberhumer
+Martijn Koster
+Martin C. Martin
+Martin Drasar
+Martin Hager
+Martin Hedenfalk
+Martin Jansen
+Martin Lemke
+Martin Skinner
+Martin Storsjo
+Marty Kuhrt
+Maruko
+Massimiliano Ziccardi
+Massimo Callegari
+Mateusz Loskot
+Mathias Axelsson
+Mats Lidell
+Matt Arsenault
+Matt Kraai
+Matt Veenstra
+Matt Witherspoon
+Matt Wixson
+Matteo Rocco
+Matthew Blain
+Matthew Clarke
+Matthias Bolte
+Maurice Barnum
+Mauro Iorio
+Max Katsev
+Maxim Ivanov
+Maxim Perenesenko
+Maxim Prohorov
+Maxime Larocque
+Mehmet Bozkurt
+Mekonikum
+Mettgut Jamalla
+Michael Benedict
+Michael Calmer
+Michael Cronenworth
+Michael Curtis
+Michael Day
+Michael Goffioul
+Michael Jahn
+Michael Jerris
+Michael Mealling
+Michael Mueller
+Michael Smith
+Michael Stillwell
+Michael Wallner
+Michal Bonino
+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
+Mike Revi
+Miklos Nemeth
+Mitz Wark
+Mohamed Lrhazi
+Mohun Biswas
+Moonesamy
+Myk Taylor
+Nach M. S.
+Nathan Coulter
+Nathan O'Sullivan
+Nathanael Nerode
+Naveen Chandran
+Naveen Noel
+Neil Bowers
+Neil Dunbar
+Neil Spring
+Nic Roets
+Nicholas Maniscalco
+Nick Gimbrone
+Nick Humfrey
+Nick Zitzmann
+Nico Baggus
+Nicolas Berloquin
+Nicolas Croiset
+Nicolas François
+Niels van Tongeren
+Nikita Schmidt
+Nikitinskit Dmitriy
+Niklas Angebrand
+Nikolai Kondrashov
+Nikos Mavrogiannopoulos
+Ning Dong
+Nir Soffer
+Nis Jorgensen
+Nodak Sodak
+Norbert Frese
+Norbert Novotny
+Ofer
+Olaf Flebbe
+Olaf Stueben
+Olaf Stüben
+Oliver Gondža
+Olivier Berger
+Oren Tirosh
+Ori Avtalion
+Oscar Koeroo
+Oscar Norlander
+P R Schaffner
+Paolo Piacentini
+Pascal Terjan
+Pasha Kuznetsov
+Pat Ray
+Patrice Guerin
+Patricia Muscalu
+Patrick Bihan-Faou
+Patrick Monnerat
+Patrick Scott
+Patrick Smith
+Patrik Thunstrom
+Pau Garcia i Quiles
+Paul Harrington
+Paul Howarth
+Paul Marquis
+Paul Moore
+Paul Nolan
+Paul Querna
+Pavel Cenek
+Pavel Orehov
+Pavel Raiskup
+Pawel A. Gajda
+Pawel Kierski
+Pedro Larroy
+Pedro Neves
+Pete Su
+Peter Bray
+Peter Forret
+Peter Gal
+Peter Heuchert
+Peter Hjalmarsson
+Peter Korsgaard
+Peter Lamberg
+Peter O'Gorman
+Peter Pentchev
+Peter Silva
+Peter Su
+Peter Sylvester
+Peter Todd
+Peter Verhas
+Peter Wullinger
+Peteris Krumins
+Phil Blundell
+Phil Karn
+Phil Lisiecki
+Phil Pellouchoud
+Philip Craig
+Philip Gladstone
+Philip Langdale
+Philippe Hameau
+Philippe Raoult
+Philippe Vaucher
+Pierre
+Pierre Brico
+Pierre Chapuis
+Pierre Joye
+Pierre Ynard
+Pooyan McSporran
+Pramod Sharma
+Puneet Pawaia
+Quagmire
+Quanah Gibson-Mount
+Quinn Slack
+Rafa Muyo
+Rafael Sagula
+Rainer Canavan
+Rainer Jung
+Rainer Koenig
+Rajesh Naganathan
+Ralf S. Engelschall
+Ralph Beckmann
+Ralph Mitchell
+Ramana Mokkapati
+Randy McMurchy
+Ravi Pratap
+Ray Dassen
+Ray Pekowski
+Reinout van Schouwen
+Renato Botelho
+Renaud Chaillat
+Renaud Duhaut
+Renaud Guillard
+Rene Bernhardt
+Rene Rebe
+Reuven Wachtfogel
+Reza Arbab
+Ricardo Cadime
+Rich Gray
+Rich Rauenzahn
+Richard Archer
+Richard Atterer
+Richard Bramante
+Richard Clayton
+Richard Cooper
+Richard Gorton
+Richard Michael
+Richard Prescott
+Richard Silverman
+Rick Jones
+Rick Richardson
+Rob Crittenden
+Rob Jones
+Rob Stanzel
+Rob Ward
+Robert A. Monat
+Robert B. Harris
+Robert D. Young
+Robert Foreman
+Robert Iakobashvili
+Robert Olson
+Robert Schumann
+Robert Weaver
+Robert Wruck
+Robin Cornelius
+Robin Johnson
+Robin Kay
+Robson Braga Araujo
+Rodney Simmons
+Rodrigo Silva
+Roland Blom
+Roland Krikava
+Roland Zimmermann
+Rolland Dudemaine
+Roman Koifman
+Roman Mamedov
+Ron Zapp
+Rosimildo da Silva
+Roy Shan
+Rune Kleveland
+Ruslan Gazizov
+Rutger Hofman
+Ryan Chan
+Ryan Nelson
+Ryan Schmidt
+S. Moonesamy
+Salvador Dávila
+Salvatore Sorrentino
+Sam Deane
+Sam Listopad
+Sampo Kellomaki
+Samuel Díaz García
+Samuel Listopad
+Samuel Thibault
+Sander Gates
+Sandor Feldi
+Santhana Todatry
+Saqib Ali
+Sara Golemon
+Saran Neti
+Saul good
+Scott Bailey
+Scott Barrett
+Scott Cantor
+Scott Davis
+Scott McCreary
+Sebastian Rasmussen
+Sebastien Willemijns
+Senthil Raja Velu
+Sergei Nikulov
+Sergio Ballestrero
+Seshubabu Pasam
+Sh Diao
+Sharad Gupta
+Shard
+Shawn Poulson
+Shmulik Regev
+Siddhartha Prakash Jain
+Sidney San Martin
+Siegfried Gyuricsko
+Simon Dick
+Simon Josefsson
+Simon Liu
+Song Ma
+Sonia Subramanian
+Spacen Jasset
+Spiridonoff A.V
+Stadler Stephan
+Stan van de Burgt
+Stanislav Ivochkin
+Stefan Esser
+Stefan Krause
+Stefan Neis
+Stefan Teleman
+Stefan Tomanek
+Stefan Ulrich
+Stephan Bergmann
+Stephen Collyer
+Stephen Kick
+Stephen More
+Sterling Hughes
+Steve Green
+Steve H Truong
+Steve Holme
+Steve Lhomme
+Steve Little
+Steve Marx
+Steve Oliphant
+Steve Roskowski
+Steven Bazyl
+Steven G. Johnson
+Steven Gu
+Steven M. Schweda
+Steven Parkes
+Stoned Elipot
+Sven Anders
+Sven Neuhaus
+Sven Wegener
+Sébastien Willemijns
+T. Bharath
+T. Yamada
+Taneli Vahakangas
+Tanguy Fautre
+Tatsuhiro Tsujikawa
+Temprimus
+Thomas J. Moore
+Thomas Klausner
+Thomas L. Shinnick
+Thomas Lopatic
+Thomas Schwinge
+Thomas Tonino
+Tim Ansell
+Tim Baker
+Tim Bartley
+Tim Chen
+Tim Costello
+Tim Harder
+Tim Heckman
+Tim Newsome
+Tim Sneddon
+Timo Sirainen
+Tinus van den Berg
+Tobias Rundström
+Toby Peterson
+Todd A Ouska
+Todd Kulesza
+Todd Ouska
+Todd Vierling
+Tom Benoist
+Tom Donovan
+Tom Grace
+Tom Lee
+Tom Mattison
+Tom Moers
+Tom Mueller
+Tom Regner
+Tom Wright
+Tom Zerucha
+Tomas Mlcoch
+Tomas Pospisek
+Tomas Szepe
+Tomasz Lacki
+Tommie Gannert
+Tommy Tam
+Ton Voon
+Toni Moreno
+Toon Verwaest
+Tor Arntsen
+Torsten Foertsch
+Toshio Kuratomi
+Toshiyuki Maezawa
+Traian Nicolescu
+Troels Walsted Hansen
+Troy Engel
+Tupone Alfredo
+Ulf Härnhammar
+Ulrich Doehner
+Ulrich Zadow
+Venkat Akella
+Victor Snezhko
+Vikram Saxena
+Vilmos Nebehaj
+Vincent Bronner
+Vincent Le Normand
+Vincent Penquerc'h
+Vincent Sanders
+Vincent Torri
+Vlad Grachov
+Vlad Ureche
+Vladimir Grishchenko
+Vladimir Lazarenko
+Vojtech Janota
+Vojtech Minarik
+Vsevolod Novikov
+Walter J. Mack
+Ward Willats
+Wayne Haigh
+Werner Koch
+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
+Yukihiro Kawada
+Yuriy Sosov
+Yves Arrouye
+Yves Lejeune
+Zdenek Pavlas
+Zekun Ni
+Zmey Petroff
+Zvi Har'El
+nk
+swalkaus at yahoo.com
+tommink[at]post.pl
diff --git a/libs/libcurl/docs/TODO b/libs/libcurl/docs/TODO
new file mode 100644
index 0000000000..8b133dc160
--- /dev/null
+++ b/libs/libcurl/docs/TODO
@@ -0,0 +1,700 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ Things that could be nice to do in the future
+
+ Things to do in project cURL. Please tell us what you think, contribute and
+ send us patches that improve things!
+
+ All bugs documented in the KNOWN_BUGS document are subject for fixing!
+
+ 1. libcurl
+ 1.2 More data sharing
+ 1.3 struct lifreq
+ 1.4 signal-based resolver timeouts
+ 1.5 get rid of PATH_MAX
+ 1.6 Happy Eyeball dual stack connect
+ 1.7 Modified buffer size approach
+
+ 2. libcurl - multi interface
+ 2.1 More non-blocking
+ 2.2 Fix HTTP Pipelining for PUT
+
+ 3. Documentation
+ 3.1 More and better
+
+ 4. FTP
+ 4.1 HOST
+ 4.2 Alter passive/active on failure and retry
+ 4.3 Earlier bad letter detection
+ 4.4 REST for large files
+ 4.5 FTP proxy support
+ 4.6 ASCII support
+
+ 5. HTTP
+ 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
+ 6.2 ditch telnet-specific select
+ 6.3 feature negotiation debug data
+ 6.4 send data in chunks
+
+ 7. SMTP
+ 7.1 Pipelining
+ 7.2 Graceful base64 decoding failure
+ 7.3 Enhanced capability support
+
+ 8. POP3
+ 8.1 Pipelining
+ 8.2 Graceful base64 decoding failure
+ 8.3 Enhanced capability support
+
+ 9. IMAP
+ 9.1 Graceful base64 decoding failure
+ 9.2 Enhanced capability support
+
+ 10. LDAP
+ 10.1 SASL based authentication mechanisms
+
+ 11. New protocols
+ 11.1 RSYNC
+
+ 12. SSL
+ 12.1 Disable specific versions
+ 12.2 Provide mutex locking API
+ 12.3 Evaluate SSL patches
+ 12.4 Cache OpenSSL contexts
+ 12.5 Export session ids
+ 12.6 Provide callback for cert verification
+ 12.7 Support other SSL libraries
+ 12.8 improve configure --with-ssl
+ 12.9 Support DANE
+
+ 13. GnuTLS
+ 13.1 SSL engine stuff
+ 13.2 check connection
+
+ 14. SASL
+ 14.1 Other authentication mechanisms
+
+ 15. Client
+ 15.1 sync
+ 15.2 glob posts
+ 15.3 prevent file overwriting
+ 15.4 simultaneous parallel transfers
+ 15.5 provide formpost headers
+ 15.6 url-specific options
+ 15.7 warning when setting an option
+ 15.8 IPv6 addresses with globbing
+
+ 16. Build
+ 16.1 roffit
+
+ 17. Test suite
+ 17.1 SSL tunnel
+ 17.2 nicer lacking perl message
+ 17.3 more protocols supported
+ 17.4 more platforms supported
+
+ 18. Next SONAME bump
+ 18.1 http-style HEAD output for ftp
+ 18.2 combine error codes
+ 18.3 extend CURLOPT_SOCKOPTFUNCTION prototype
+
+ 19. Next major release
+ 19.1 cleanup return codes
+ 19.2 remove obsolete defines
+ 19.3 size_t
+ 19.4 remove several functions
+ 19.5 remove CURLOPT_FAILONERROR
+ 19.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE
+ 19.7 remove progress meter from libcurl
+ 19.8 remove 'curl_httppost' from public
+ 19.9 have form functions use CURL handle argument
+ 19.10 Add CURLOPT_MAIL_CLIENT option
+
+==============================================================================
+
+1. libcurl
+
+1.2 More data sharing
+
+ curl_share_* functions already exist and work, and they can be extended to
+ share more. For example, enable sharing of the ares channel and the
+ connection cache.
+
+1.3 struct lifreq
+
+ Use 'struct lifreq' and SIOCGLIFADDR instead of 'struct ifreq' and
+ SIOCGIFADDR on newer Solaris versions as they claim the latter is obsolete.
+ To support ipv6 interface addresses for network interfaces properly.
+
+1.4 signal-based resolver timeouts
+
+ libcurl built without an asynchronous resolver library uses alarm() to time
+ out DNS lookups. When a timeout occurs, this causes libcurl to jump from the
+ signal handler back into the library with a sigsetjmp, which effectively
+ causes libcurl to continue running within the signal handler. This is
+ non-portable and could cause problems on some platforms. A discussion on the
+ problem is available at http://curl.haxx.se/mail/lib-2008-09/0197.html
+
+ Also, alarm() provides timeout resolution only to the nearest second. alarm
+ ought to be replaced by setitimer on systems that support it.
+
+1.5 get rid of PATH_MAX
+
+ Having code use and rely on PATH_MAX is not nice:
+ http://insanecoding.blogspot.com/2007/11/pathmax-simply-isnt.html
+
+ Currently the SSH based code uses it a bit, but to remove PATH_MAX from there
+ 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 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
+ option existing simultaneously there are reasons to reconsider internal
+ choices.
+
+ To make libcurl do blazing fast IPv6 in a dual-stack configuration, this needs
+ to be addressed:
+
+ 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
+
+ Make sure we don't ever loop because of non-blocking sockets returning
+ EWOULDBLOCK or similar. Blocking cases include:
+
+ - Name resolves on non-windows unless c-ares is used
+ - NSS SSL connections
+ - HTTP proxy CONNECT operations
+ - SOCKS proxy handshakes
+ - file:// transfers
+ - TELNET transfers
+ - The "DONE" operation (post transfer protocol-specific actions) for the
+ protocols SFTP, SMTP, FTP. Fixing Curl_done() for this is a worthy task.
+
+2.2 Fix HTTP Pipelining for PUT
+
+ HTTP Pipelining can be a way to greatly enhance performance for multiple
+ serial requests and currently libcurl only supports that for HEAD and GET
+ requests but it should also be possible for PUT.
+
+3. Documentation
+
+3.1 More and better
+
+ Exactly
+
+4. FTP
+
+4.1 HOST
+
+ HOST is a suggested command in the works for a client to tell which host name
+ to use, to offer FTP servers named-based virtual hosting:
+
+ http://tools.ietf.org/html/draft-hethmon-mcmurray-ftp-hosts-11
+
+4.2 Alter passive/active on failure and retry
+
+ When trying to connect passively to a server which only supports active
+ connections, libcurl returns CURLE_FTP_WEIRD_PASV_REPLY and closes the
+ connection. There could be a way to fallback to an active connection (and
+ vice versa). http://curl.haxx.se/bug/feature.cgi?id=1754793
+
+4.3 Earlier bad letter detection
+
+ Make the detection of (bad) %0d and %0a codes in FTP url parts earlier in the
+ process to avoid doing a resolve and connect in vain.
+
+4.4 REST for large files
+
+ REST fix for servers not behaving well on >2GB requests. This should fail if
+ the server doesn't set the pointer to the requested index. The tricky
+ (impossible?) part is to figure out if the server did the right thing or not.
+
+4.5 FTP proxy support
+
+ Support the most common FTP proxies, Philip Newton provided a list allegedly
+ from ncftp. This is not a subject without debate, and is probably not really
+ suitable for libcurl. http://curl.haxx.se/mail/archive-2003-04/0126.html
+
+4.6 ASCII support
+
+ FTP ASCII transfers do not follow RFC959. They don't convert the data
+ accordingly.
+
+5. HTTP
+
+5.1 Better persistency for HTTP 1.0
+
+ "Better" support for persistent connections over HTTP 1.0
+ http://curl.haxx.se/bug/feature.cgi?id=1089001
+
+5.2 support FF3 sqlite cookie files
+
+ Firefox 3 is changing from its former format to a a sqlite database instead.
+ We should consider how (lib)curl can/should support this.
+ http://curl.haxx.se/bug/feature.cgi?id=1871388
+
+5.3 Rearrange request header order
+
+ Server implementors often make an effort to detect browser and to reject
+ clients it can detect to not match. One of the last details we cannot yet
+ control in libcurl's HTTP requests, which also can be exploited to detect
+ that libcurl is in fact used even when it tries to impersonate a browser, is
+ the order of the request headers. I propose that we introduce a new option in
+ which you give headers a value, and then when the HTTP request is built it
+ sorts the headers based on that number. We could then have internally created
+ 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
+
+Reading input (to send to the remote server) on stdin is a crappy solution for
+library purposes. We need to invent a good way for the application to be able
+to provide the data to send.
+
+6.2 ditch telnet-specific select
+
+ Move the telnet support's network select() loop go away and merge the code
+ into the main transfer loop. Until this is done, the multi interface won't
+ work for telnet.
+
+6.3 feature negotiation debug data
+
+ Add telnet feature negotiation data to the debug callback as header data.
+
+6.4 send data in chunks
+
+ Currently, telnet sends data one byte at a time. This is fine for interactive
+ use, but inefficient for any other. Sent data should be sent in larger
+ chunks.
+
+7. SMTP
+
+7.1 Pipelining
+
+ Add support for pipelining emails.
+
+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 Pipelining
+
+ Add support for pipelining commands.
+
+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 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
+
+ Currently the LDAP module only supports ldap_simple_bind_s() in order to bind
+ to an LDAP server. However, this function sends username and password details
+ using the simple authentication mechanism (as clear text). However, it should
+ be possible to use ldap_bind_s() instead specifing the security context
+ information ourselves.
+
+11. New protocols
+
+11.1 RSYNC
+
+ There's no RFC for the protocol or an URI/URL format. An implementation
+ should most probably use an existing rsync library, such as librsync.
+
+12. SSL
+
+12.1 Disable specific versions
+
+ Provide an option that allows for disabling specific SSL versions, such as
+ SSLv2 http://curl.haxx.se/bug/feature.cgi?id=1767276
+
+12.2 Provide mutex locking API
+
+ Provide a libcurl API for setting mutex callbacks in the underlying SSL
+ library, so that the same application code can use mutex-locking
+ independently of OpenSSL or GnutTLS being used.
+
+12.3 Evaluate SSL patches
+
+ Evaluate/apply Gertjan van Wingerde's SSL patches:
+ http://curl.haxx.se/mail/lib-2004-03/0087.html
+
+12.4 Cache OpenSSL contexts
+
+ "Look at SSL cafile - quick traces look to me like these are done on every
+ request as well, when they should only be necessary once per ssl context (or
+ once per handle)". The major improvement we can rather easily do is to make
+ sure we don't create and kill a new SSL "context" for every request, but
+ instead make one for every connection and re-use that SSL context in the same
+ style connections are re-used. It will make us use slightly more memory but
+ it will libcurl do less creations and deletions of SSL contexts.
+
+12.5 Export session ids
+
+ Add an interface to libcurl that enables "session IDs" to get
+ exported/imported. Cris Bailiff said: "OpenSSL has functions which can
+ serialise the current SSL state to a buffer of your choice, and recover/reset
+ the state from such a buffer at a later date - this is used by mod_ssl for
+ apache to implement and SSL session ID cache".
+
+12.6 Provide callback for cert verification
+
+ OpenSSL supports a callback for customised verification of the peer
+ certificate, but this doesn't seem to be exposed in the libcurl APIs. Could
+ it be? There's so much that could be done if it were!
+
+12.7 Support other SSL libraries
+
+ Make curl's SSL layer capable of using other free SSL libraries. Such as
+ MatrixSSL (http://www.matrixssl.org/).
+
+12.8 improve configure --with-ssl
+
+ make the configure --with-ssl option first check for OpenSSL, then GnuTLS,
+ then NSS...
+
+12.9 Support DANE
+
+ DNS-Based Authentication of Named Entities (DANE) is a way to provide SSL
+ 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
+
+ Is this even possible?
+
+13.2 check connection
+
+ Add a way to check if the connection seems to be alive, to correspond to the
+ SSL_peak() way we use with OpenSSL.
+
+14. SASL
+
+14.1 Other authentication mechanisms
+
+ Add support for GSSAPI to SMTP, POP3 and IMAP.
+
+15. Client
+
+15.1 sync
+
+ "curl --sync http://example.com/feed[1-100].rss" or
+ "curl --sync http://example.net/{index,calendar,history}.html"
+
+ Downloads a range or set of URLs using the remote name, but only if the
+ remote file is newer than the local file. A Last-Modified HTTP date header
+ should also be used to set the mod date on the downloaded file.
+
+15.2 glob posts
+
+ Globbing support for -d and -F, as in 'curl -d "name=foo[0-9]" URL'.
+ This is easily scripted though.
+
+15.3 prevent file overwriting
+
+ Add an option that prevents cURL from overwriting existing local files. When
+ used, and there already is an existing file with the target file name
+ (either -O or -o), a number should be appended (and increased if already
+ existing). So that index.html becomes first index.html.1 and then
+ index.html.2 etc.
+
+15.4 simultaneous parallel transfers
+
+ The client could be told to use maximum N simultaneous parallel transfers and
+ then just make sure that happens. It should of course not make more than one
+ connection to the same remote host. This would require the client to use the
+ multi interface. http://curl.haxx.se/bug/feature.cgi?id=1558595
+
+15.5 provide formpost headers
+
+ Extending the capabilities of the multipart formposting. How about leaving
+ the ';type=foo' syntax as it is and adding an extra tag (headers) which
+ works like this: curl -F "coolfiles=@fil1.txt;headers=@fil1.hdr" where
+ fil1.hdr contains extra headers like
+
+ Content-Type: text/plain; charset=KOI8-R"
+ Content-Transfer-Encoding: base64
+ X-User-Comment: Please don't use browser specific HTML code
+
+ which should overwrite the program reasonable defaults (plain/text,
+ 8bit...)
+
+15.6 url-specific options
+
+ Provide a way to make options bound to a specific URL among several on the
+ command line. Possibly by letting ':' separate options between URLs,
+ similar to this:
+
+ curl --data foo --url url.com : \
+ --url url2.com : \
+ --url url3.com --data foo3
+
+ (More details: http://curl.haxx.se/mail/archive-2004-07/0133.html)
+
+ The example would do a POST-GET-POST combination on a single command line.
+
+15.7 warning when setting an option
+
+ Display a warning when libcurl returns an error when setting an option.
+ This can be useful to tell when support for a particular feature hasn't been
+ compiled into the library.
+
+15.8 IPv6 addresses with globbing
+
+ Currently the command line client needs to get url globbing disabled (with
+ -g) for it to support IPv6 numerical addresses. This is a rather silly flaw
+ that should be corrected. It probably involves a smarter detection of the
+ '[' and ']' letters.
+
+16. Build
+
+16.1 roffit
+
+ Consider extending 'roffit' to produce decent ASCII output, and use that
+ instead of (g)nroff when building src/tool_hugehelp.c
+
+17. Test suite
+
+17.1 SSL tunnel
+
+ Make our own version of stunnel for simple port forwarding to enable HTTPS
+ and FTP-SSL tests without the stunnel dependency, and it could allow us to
+ provide test tools built with either OpenSSL or GnuTLS
+
+17.2 nicer lacking perl message
+
+ If perl wasn't found by the configure script, don't attempt to run the tests
+ but explain something nice why it doesn't.
+
+17.3 more protocols supported
+
+ Extend the test suite to include more protocols. The telnet could just do ftp
+ or http operations (for which we have test servers).
+
+17.4 more platforms supported
+
+ Make the test suite work on more platforms. OpenBSD and Mac OS. Remove
+ fork()s and it should become even more portable.
+
+18. Next SONAME bump
+
+18.1 http-style HEAD output for ftp
+
+ #undef CURL_FTP_HTTPSTYLE_HEAD in lib/ftp.c to remove the HTTP-style headers
+ from being output in NOBODY requests over ftp
+
+18.2 combine error codes
+
+ Combine some of the error codes to remove duplicates. The original
+ numbering should not be changed, and the old identifiers would be
+ macroed to the new ones in an CURL_NO_OLDIES section to help with
+ backward compatibility.
+
+ Candidates for removal and their replacements:
+
+ CURLE_FILE_COULDNT_READ_FILE => CURLE_REMOTE_FILE_NOT_FOUND
+
+ CURLE_FTP_COULDNT_RETR_FILE => CURLE_REMOTE_FILE_NOT_FOUND
+
+ CURLE_FTP_COULDNT_USE_REST => CURLE_RANGE_ERROR
+
+ CURLE_FUNCTION_NOT_FOUND => CURLE_FAILED_INIT
+
+ CURLE_LDAP_INVALID_URL => CURLE_URL_MALFORMAT
+
+ CURLE_TFTP_NOSUCHUSER => CURLE_TFTP_ILLEGAL
+
+ CURLE_TFTP_NOTFOUND => CURLE_REMOTE_FILE_NOT_FOUND
+
+ CURLE_TFTP_PERM => CURLE_REMOTE_ACCESS_DENIED
+
+18.3 extend CURLOPT_SOCKOPTFUNCTION prototype
+
+ The current prototype only provides 'purpose' that tells what the
+ connection/socket is for, but not any protocol or similar. It makes it hard
+ for applications to differentiate on TCP vs UDP and even HTTP vs FTP and
+ similar.
+
+10. Next major release
+
+19.1 cleanup return codes
+
+ curl_easy_cleanup() returns void, but curl_multi_cleanup() returns a
+ CURLMcode. These should be changed to be the same.
+
+19.2 remove obsolete defines
+
+ remove obsolete defines from curl/curl.h
+
+19.3 size_t
+
+ make several functions use size_t instead of int in their APIs
+
+19.4 remove several functions
+
+ remove the following functions from the public API:
+
+ curl_getenv
+
+ curl_mprintf (and variations)
+
+ curl_strequal
+
+ curl_strnequal
+
+ They will instead become curlx_ - alternatives. That makes the curl app
+ still capable of using them, by building with them from source.
+
+ These functions have no purpose anymore:
+
+ curl_multi_socket
+
+ curl_multi_socket_all
+
+19.5 remove CURLOPT_FAILONERROR
+
+ Remove support for CURLOPT_FAILONERROR, it has gotten too kludgy and weird
+ internally. Let the app judge success or not for itself.
+
+19.6 remove CURLOPT_DNS_USE_GLOBAL_CACHE
+
+ Remove support for a global DNS cache. Anything global is silly, and we
+ already offer the share interface for the same functionality but done
+ "right".
+
+19.7 remove progress meter from libcurl
+
+ The internally provided progress meter output doesn't belong in the library.
+ Basically no application wants it (apart from curl) but instead applications
+ can and should do their own progress meters using the progress callback.
+
+ The progress callback should then be bumped as well to get proper 64bit
+ variable types passed to it instead of doubles so that big files work
+ correctly.
+
+19.8 remove 'curl_httppost' from public
+
+ curl_formadd() was made to fill in a public struct, but the fact that the
+ struct is public is never really used by application for their own advantage
+ but instead often restricts how the form functions can or can't be modified.
+
+ Changing them to return a private handle will benefit the implementation and
+ allow us much greater freedoms while still maintining a solid API and ABI.
+
+19.9 have form functions use CURL handle argument
+
+ curl_formadd() and curl_formget() both currently have no CURL handle
+ argument, but both can use a callback that is set in the easy handle, and
+ thus curl_formget() with callback cannot function without first having
+ curl_easy_perform() (or similar) called - which is hard to grasp and a design
+ mistake.
+
+19.10 Add CURLOPT_MAIL_CLIENT option
+
+ Rather than use the URL to specify the mail client string to present in the
+ HELO and EHLO commands, libcurl should support a new CURLOPT specifically for
+ specifing this data as the URL is non-standard and to be honest a bit of a
+ hack ;-)
+
+ Please see the following thread for more information:
+ http://curl.haxx.se/mail/lib-2012-05/0178.html
+
diff --git a/libs/libcurl/docs/TheArtOfHttpScripting b/libs/libcurl/docs/TheArtOfHttpScripting
new file mode 100644
index 0000000000..b0dab5ff2c
--- /dev/null
+++ b/libs/libcurl/docs/TheArtOfHttpScripting
@@ -0,0 +1,507 @@
+Online: http://curl.haxx.se/docs/httpscripting.html
+Date: Jan 19, 2011
+
+ The Art Of Scripting HTTP Requests Using Curl
+ =============================================
+
+ This document will assume that you're familiar with HTML and general
+ networking.
+
+ The possibility to write scripts is essential to make a good computer
+ system. Unix' capability to be extended by shell scripts and various tools to
+ run various automated commands and scripts is one reason why it has succeeded
+ so well.
+
+ The increasing amount of applications moving to the web has made "HTTP
+ Scripting" more frequently requested and wanted. To be able to automatically
+ extract information from the web, to fake users, to post or upload data to
+ web servers are all important tasks today.
+
+ Curl is a command line tool for doing all sorts of URL manipulations and
+ transfers, but this particular document will focus on how to use it when
+ doing HTTP requests for fun and profit. I'll assume that you know how to
+ invoke 'curl --help' or 'curl --manual' to get basic information about it.
+
+ Curl is not written to do everything for you. It makes the requests, it gets
+ the data, it sends data and it retrieves the information. You probably need
+ to glue everything together using some kind of script language or repeated
+ manual invokes.
+
+1. The HTTP Protocol
+
+ HTTP is the protocol used to fetch data from web servers. It is a very simple
+ protocol that is built upon TCP/IP. The protocol also allows information to
+ get sent to the server from the client using a few different methods, as will
+ be shown here.
+
+ HTTP is plain ASCII text lines being sent by the client to a server to
+ request a particular action, and then the server replies a few text lines
+ before the actual requested content is sent to the client.
+
+ The client, curl, sends a HTTP request. The request contains a method (like
+ GET, POST, HEAD etc), a number of request headers and sometimes a request
+ body. The HTTP server responds with a status line (indicating if things went
+ well), response headers and most often also a response body. The "body" part
+ is the plain data you requested, like the actual HTML or the image etc.
+
+ 1.1 See the Protocol
+
+ Using curl's option --verbose (-v as a short option) will display what kind
+ of commands curl sends to the server, as well as a few other informational
+ texts.
+
+ --verbose is the single most useful option when it comes to debug or even
+ understand the curl<->server interaction.
+
+ Sometimes even --verbose is not enough. Then --trace and --trace-ascii offer
+ even more details as they show EVERYTHING curl sends and receives. Use it
+ like this:
+
+ curl --trace-ascii debugdump.txt http://www.example.com/
+
+2. URL
+
+ The Uniform Resource Locator format is how you specify the address of a
+ particular resource on the Internet. You know these, you've seen URLs like
+ http://curl.haxx.se or https://yourbank.com a million times.
+
+3. GET a page
+
+ The simplest and most common request/operation made using HTTP is to get a
+ URL. The URL could itself refer to a web page, an image or a file. The client
+ issues a GET request to the server and receives the document it asked for.
+ If you issue the command line
+
+ curl http://curl.haxx.se
+
+ you get a web page returned in your terminal window. The entire HTML document
+ that that URL holds.
+
+ All HTTP replies contain a set of response headers that are normally hidden,
+ use curl's --include (-i) option to display them as well as the rest of the
+ document. You can also ask the remote server for ONLY the headers by using
+ the --head (-I) option (which will make curl issue a HEAD request).
+
+4. Forms
+
+ Forms are the general way a web site can present a HTML page with fields for
+ the user to enter data in, and then press some kind of 'OK' or 'submit'
+ button to get that data sent to the server. The server then typically uses
+ the posted data to decide how to act. Like using the entered words to search
+ in a database, or to add the info in a bug track system, display the entered
+ address on a map or using the info as a login-prompt verifying that the user
+ is allowed to see what it is about to see.
+
+ Of course there has to be some kind of program in the server end to receive
+ the data you send. You cannot just invent something out of the air.
+
+ 4.1 GET
+
+ A GET-form uses the method GET, as specified in HTML like:
+
+ <form method="GET" action="junk.cgi">
+ <input type=text name="birthyear">
+ <input type=submit name=press value="OK">
+ </form>
+
+ In your favorite browser, this form will appear with a text box to fill in
+ and a press-button labeled "OK". If you fill in '1905' and press the OK
+ button, your browser will then create a new URL to get for you. The URL will
+ get "junk.cgi?birthyear=1905&press=OK" appended to the path part of the
+ previous URL.
+
+ If the original form was seen on the page "www.hotmail.com/when/birth.html",
+ the second page you'll get will become
+ "www.hotmail.com/when/junk.cgi?birthyear=1905&press=OK".
+
+ Most search engines work this way.
+
+ To make curl do the GET form post for you, just enter the expected created
+ URL:
+
+ curl "http://www.hotmail.com/when/junk.cgi?birthyear=1905&press=OK"
+
+ 4.2 POST
+
+ The GET method makes all input field names get displayed in the URL field of
+ your browser. That's generally a good thing when you want to be able to
+ bookmark that page with your given data, but it is an obvious disadvantage
+ if you entered secret information in one of the fields or if there are a
+ large amount of fields creating a very long and unreadable URL.
+
+ The HTTP protocol then offers the POST method. This way the client sends the
+ data separated from the URL and thus you won't see any of it in the URL
+ address field.
+
+ The form would look very similar to the previous one:
+
+ <form method="POST" action="junk.cgi">
+ <input type=text name="birthyear">
+ <input type=submit name=press value=" OK ">
+ </form>
+
+ And to use curl to post this form with the same data filled in as before, we
+ could do it like:
+
+ curl --data "birthyear=1905&press=%20OK%20" \
+ http://www.example.com/when.cgi
+
+ This kind of POST will use the Content-Type
+ application/x-www-form-urlencoded and is the most widely used POST kind.
+
+ The data you send to the server MUST already be properly encoded, curl will
+ not do that for you. For example, if you want the data to contain a space,
+ you need to replace that space with %20 etc. Failing to comply with this
+ will most likely cause your data to be received wrongly and messed up.
+
+ Recent curl versions can in fact url-encode POST data for you, like this:
+
+ curl --data-urlencode "name=I am Daniel" http://www.example.com
+
+ 4.3 File Upload POST
+
+ Back in late 1995 they defined an additional way to post data over HTTP. It
+ is documented in the RFC 1867, why this method sometimes is referred to as
+ RFC1867-posting.
+
+ This method is mainly designed to better support file uploads. A form that
+ allows a user to upload a file could be written like this in HTML:
+
+ <form method="POST" enctype='multipart/form-data' action="upload.cgi">
+ <input type=file name=upload>
+ <input type=submit name=press value="OK">
+ </form>
+
+ This clearly shows that the Content-Type about to be sent is
+ multipart/form-data.
+
+ To post to a form like this with curl, you enter a command line like:
+
+ curl --form upload=@localfilename --form press=OK [URL]
+
+ 4.4 Hidden Fields
+
+ A very common way for HTML based application to pass state information
+ between pages is to add hidden fields to the forms. Hidden fields are
+ already filled in, they aren't displayed to the user and they get passed
+ along just as all the other fields.
+
+ A similar example form with one visible field, one hidden field and one
+ submit button could look like:
+
+ <form method="POST" action="foobar.cgi">
+ <input type=text name="birthyear">
+ <input type=hidden name="person" value="daniel">
+ <input type=submit name="press" value="OK">
+ </form>
+
+ To post this with curl, you won't have to think about if the fields are
+ hidden or not. To curl they're all the same:
+
+ curl --data "birthyear=1905&press=OK&person=daniel" [URL]
+
+ 4.5 Figure Out What A POST Looks Like
+
+ When you're about fill in a form and send to a server by using curl instead
+ of a browser, you're of course very interested in sending a POST exactly the
+ way your browser does.
+
+ An easy way to get to see this, is to save the HTML page with the form on
+ your local disk, modify the 'method' to a GET, and press the submit button
+ (you could also change the action URL if you want to).
+
+ You will then clearly see the data get appended to the URL, separated with a
+ '?'-letter as GET forms are supposed to.
+
+5. PUT
+
+ The perhaps best way to upload data to a HTTP server is to use PUT. Then
+ again, this of course requires that someone put a program or script on the
+ server end that knows how to receive a HTTP PUT stream.
+
+ Put a file to a HTTP server with curl:
+
+ curl --upload-file uploadfile http://www.example.com/receive.cgi
+
+6. HTTP Authentication
+
+ HTTP Authentication is the ability to tell the server your username and
+ password so that it can verify that you're allowed to do the request you're
+ doing. The Basic authentication used in HTTP (which is the type curl uses by
+ default) is *plain* *text* based, which means it sends username and password
+ only slightly obfuscated, but still fully readable by anyone that sniffs on
+ the network between you and the remote server.
+
+ To tell curl to use a user and password for authentication:
+
+ curl --user name:password http://www.example.com
+
+ The site might require a different authentication method (check the headers
+ returned by the server), and then --ntlm, --digest, --negotiate or even
+ --anyauth might be options that suit you.
+
+ Sometimes your HTTP access is only available through the use of a HTTP
+ proxy. This seems to be especially common at various companies. A HTTP proxy
+ may require its own user and password to allow the client to get through to
+ the Internet. To specify those with curl, run something like:
+
+ curl --proxy-user proxyuser:proxypassword curl.haxx.se
+
+ If your proxy requires the authentication to be done using the NTLM method,
+ use --proxy-ntlm, if it requires Digest use --proxy-digest.
+
+ If you use any one these user+password options but leave out the password
+ part, curl will prompt for the password interactively.
+
+ Do note that when a program is run, its parameters might be possible to see
+ when listing the running processes of the system. Thus, other users may be
+ able to watch your passwords if you pass them as plain command line
+ options. There are ways to circumvent this.
+
+ It is worth noting that while this is how HTTP Authentication works, very
+ many web sites will not use this concept when they provide logins etc. See
+ the Web Login chapter further below for more details on that.
+
+7. Referer
+
+ A HTTP request may include a 'referer' field (yes it is misspelled), which
+ can be used to tell from which URL the client got to this particular
+ resource. Some programs/scripts check the referer field of requests to verify
+ that this wasn't arriving from an external site or an unknown page. While
+ this is a stupid way to check something so easily forged, many scripts still
+ do it. Using curl, you can put anything you want in the referer-field and
+ thus more easily be able to fool the server into serving your request.
+
+ Use curl to set the referer field with:
+
+ curl --referer http://www.example.come http://www.example.com
+
+8. User Agent
+
+ Very similar to the referer field, all HTTP requests may set the User-Agent
+ field. It names what user agent (client) that is being used. Many
+ applications use this information to decide how to display pages. Silly web
+ programmers try to make different pages for users of different browsers to
+ make them look the best possible for their particular browsers. They usually
+ also do different kinds of javascript, vbscript etc.
+
+ At times, you will see that getting a page with curl will not return the same
+ page that you see when getting the page with your browser. Then you know it
+ is time to set the User Agent field to fool the server into thinking you're
+ one of those browsers.
+
+ To make curl look like Internet Explorer 5 on a Windows 2000 box:
+
+ curl --user-agent "Mozilla/4.0 (compatible; MSIE 5.01; Windows NT 5.0)" [URL]
+
+ Or why not look like you're using Netscape 4.73 on an old Linux box:
+
+ curl --user-agent "Mozilla/4.73 [en] (X11; U; Linux 2.2.15 i686)" [URL]
+
+9. Redirects
+
+ When a resource is requested from a server, the reply from the server may
+ include a hint about where the browser should go next to find this page, or a
+ new page keeping newly generated output. The header that tells the browser
+ to redirect is Location:.
+
+ Curl does not follow Location: headers by default, but will simply display
+ such pages in the same manner it display all HTTP replies. It does however
+ feature an option that will make it attempt to follow the Location: pointers.
+
+ To tell curl to follow a Location:
+
+ curl --location http://www.example.com
+
+ If you use curl to POST to a site that immediately redirects you to another
+ page, you can safely use --location (-L) and --data/--form together. Curl will
+ only use POST in the first request, and then revert to GET in the following
+ operations.
+
+10. Cookies
+
+ The way the web browsers do "client side state control" is by using
+ cookies. Cookies are just names with associated contents. The cookies are
+ sent to the client by the server. The server tells the client for what path
+ and host name it wants the cookie sent back, and it also sends an expiration
+ date and a few more properties.
+
+ When a client communicates with a server with a name and path as previously
+ specified in a received cookie, the client sends back the cookies and their
+ contents to the server, unless of course they are expired.
+
+ Many applications and servers use this method to connect a series of requests
+ into a single logical session. To be able to use curl in such occasions, we
+ must be able to record and send back cookies the way the web application
+ expects them. The same way browsers deal with them.
+
+ The simplest way to send a few cookies to the server when getting a page with
+ curl is to add them on the command line like:
+
+ curl --cookie "name=Daniel" http://www.example.com
+
+ Cookies are sent as common HTTP headers. This is practical as it allows curl
+ to record cookies simply by recording headers. Record cookies with curl by
+ using the --dump-header (-D) option like:
+
+ curl --dump-header headers_and_cookies http://www.example.com
+
+ (Take note that the --cookie-jar option described below is a better way to
+ store cookies.)
+
+ Curl has a full blown cookie parsing engine built-in that comes to use if you
+ want to reconnect to a server and use cookies that were stored from a
+ previous connection (or handicrafted manually to fool the server into
+ believing you had a previous connection). To use previously stored cookies,
+ you run curl like:
+
+ curl --cookie stored_cookies_in_file http://www.example.com
+
+ Curl's "cookie engine" gets enabled when you use the --cookie option. If you
+ only want curl to understand received cookies, use --cookie with a file that
+ doesn't exist. Example, if you want to let curl understand cookies from a
+ page and follow a location (and thus possibly send back cookies it received),
+ you can invoke it like:
+
+ curl --cookie nada --location http://www.example.com
+
+ Curl has the ability to read and write cookie files that use the same file
+ format that Netscape and Mozilla do. It is a convenient way to share cookies
+ between browsers and automatic scripts. The --cookie (-b) switch
+ automatically detects if a given file is such a cookie file and parses it,
+ and by using the --cookie-jar (-c) option you'll make curl write a new cookie
+ file at the end of an operation:
+
+ curl --cookie cookies.txt --cookie-jar newcookies.txt \
+ http://www.example.com
+
+11. HTTPS
+
+ There are a few ways to do secure HTTP transfers. The by far most common
+ protocol for doing this is what is generally known as HTTPS, HTTP over
+ SSL. SSL encrypts all the data that is sent and received over the network and
+ thus makes it harder for attackers to spy on sensitive information.
+
+ SSL (or TLS as the latest version of the standard is called) offers a
+ truckload of advanced features to allow all those encryptions and key
+ infrastructure mechanisms encrypted HTTP requires.
+
+ Curl supports encrypted fetches thanks to the freely available OpenSSL
+ libraries. To get a page from a HTTPS server, simply run curl like:
+
+ curl https://secure.example.com
+
+ 11.1 Certificates
+
+ In the HTTPS world, you use certificates to validate that you are the one
+ you claim to be, as an addition to normal passwords. Curl supports client-
+ side certificates. All certificates are locked with a pass phrase, which you
+ need to enter before the certificate can be used by curl. The pass phrase
+ can be specified on the command line or if not, entered interactively when
+ curl queries for it. Use a certificate with curl on a HTTPS server like:
+
+ curl --cert mycert.pem https://secure.example.com
+
+ curl also tries to verify that the server is who it claims to be, by
+ verifying the server's certificate against a locally stored CA cert
+ bundle. Failing the verification will cause curl to deny the connection. You
+ must then use --insecure (-k) in case you want to tell curl to ignore that
+ the server can't be verified.
+
+ More about server certificate verification and ca cert bundles can be read
+ in the SSLCERTS document, available online here:
+
+ http://curl.haxx.se/docs/sslcerts.html
+
+12. Custom Request Elements
+
+ Doing fancy stuff, you may need to add or change elements of a single curl
+ request.
+
+ For example, you can change the POST request to a PROPFIND and send the data
+ as "Content-Type: text/xml" (instead of the default Content-Type) like this:
+
+ curl --data "<xml>" --header "Content-Type: text/xml" \
+ --request PROPFIND url.com
+
+ You can delete a default header by providing one without content. Like you
+ can ruin the request by chopping off the Host: header:
+
+ curl --header "Host:" http://www.example.com
+
+ You can add headers the same way. Your server may want a "Destination:"
+ header, and you can add it:
+
+ curl --header "Destination: http://nowhere" http://example.com
+
+13. Web Login
+
+ While not strictly just HTTP related, it still cause a lot of people problems
+ so here's the executive run-down of how the vast majority of all login forms
+ work and how to login to them using curl.
+
+ It can also be noted that to do this properly in an automated fashion, you
+ will most certainly need to script things and do multiple curl invokes etc.
+
+ First, servers mostly use cookies to track the logged-in status of the
+ client, so you will need to capture the cookies you receive in the
+ responses. Then, many sites also set a special cookie on the login page (to
+ make sure you got there through their login page) so you should make a habit
+ of first getting the login-form page to capture the cookies set there.
+
+ Some web-based login systems features various amounts of javascript, and
+ sometimes they use such code to set or modify cookie contents. Possibly they
+ do that to prevent programmed logins, like this manual describes how to...
+ Anyway, if reading the code isn't enough to let you repeat the behavior
+ manually, capturing the HTTP requests done by your browers and analyzing the
+ sent cookies is usually a working method to work out how to shortcut the
+ javascript need.
+
+ In the actual <form> tag for the login, lots of sites fill-in random/session
+ or otherwise secretly generated hidden tags and you may need to first capture
+ the HTML code for the login form and extract all the hidden fields to be able
+ to do a proper login POST. Remember that the contents need to be URL encoded
+ when sent in a normal POST.
+
+14. Debug
+
+ Many times when you run curl on a site, you'll notice that the site doesn't
+ seem to respond the same way to your curl requests as it does to your
+ browser's.
+
+ Then you need to start making your curl requests more similar to your
+ browser's requests:
+
+ * Use the --trace-ascii option to store fully detailed logs of the requests
+ for easier analyzing and better understanding
+
+ * Make sure you check for and use cookies when needed (both reading with
+ --cookie and writing with --cookie-jar)
+
+ * Set user-agent to one like a recent popular browser does
+
+ * Set referer like it is set by the browser
+
+ * If you use POST, make sure you send all the fields and in the same order as
+ the browser does it. (See chapter 4.5 above)
+
+ A very good helper to make sure you do this right, is the LiveHTTPHeader tool
+ that lets you view all headers you send and receive with Mozilla/Firefox
+ (even when using HTTPS).
+
+ A more raw approach is to capture the HTTP traffic on the network with tools
+ such as ethereal or tcpdump and check what headers that were sent and
+ received by the browser. (HTTPS makes this technique inefficient.)
+
+15. References
+
+ RFC 2616 is a must to read if you want in-depth understanding of the HTTP
+ protocol.
+
+ RFC 3986 explains the URL syntax.
+
+ RFC 2109 defines how cookies are supposed to work.
+
+ RFC 1867 defines the HTTP post upload format.
+
+ http://curl.haxx.se is the home of the cURL project
diff --git a/libs/libcurl/docs/VERSIONS b/libs/libcurl/docs/VERSIONS
new file mode 100644
index 0000000000..0670089bdb
--- /dev/null
+++ b/libs/libcurl/docs/VERSIONS
@@ -0,0 +1,60 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+Version Numbers and Releases
+
+ Curl is not only curl. Curl is also libcurl. They're actually individually
+ versioned, but they mostly follow each other rather closely.
+
+ The version numbering is always built up using the same system:
+
+ X.Y[.Z]
+
+ Where
+ X is main version number
+ Y is release number
+ Z is patch number
+
+ One of these numbers will get bumped in each new release. The numbers to the
+ right of a bumped number will be reset to zero. If Z is zero, it may not be
+ included in the version number.
+
+ The main version number will get bumped when *really* big, world colliding
+ changes are made. The release number is bumped when changes are performed or
+ things/features are added. The patch number is bumped when the changes are
+ mere bugfixes.
+
+ It means that after release 1.2.3, we can release 2.0 if something really big
+ has been made, 1.3 if not that big changes were made or 1.2.4 if mostly bugs
+ were fixed.
+
+ Bumping, as in increasing the number with 1, is unconditionally only
+ affecting one of the numbers (except the ones to the right of it, that may be
+ set to zero). 1 becomes 2, 3 becomes 4, 9 becomes 10, 88 becomes 89 and 99
+ becomes 100. So, after 1.2.9 comes 1.2.10. After 3.99.3, 3.100 might come.
+
+ All original curl source release archives are named according to the libcurl
+ version (not according to the curl client version that, as said before, might
+ differ).
+
+ As a service to any application that might want to support new libcurl
+ features while still being able to build with older versions, all releases
+ have the libcurl version stored in the curl/curlver.h file using a static
+ numbering scheme that can be used for comparison. The version number is
+ defined as:
+
+ #define LIBCURL_VERSION_NUM 0xXXYYZZ
+
+ Where XX, YY and ZZ are the main version, release and patch numbers in
+ hexadecimal. All three number fields are always represented using two digits
+ (eight bits each). 1.2 would appear as "0x010200" while version 9.11.7
+ appears as "0x090b07".
+
+ This 6-digit hexadecimal number is always a greater number in a more recent
+ release. It makes comparisons with greater than and less than work.
+
+ This number is also available as three separate defines:
+ LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR and LIBCURL_VERSION_PATCH.
diff --git a/libs/libcurl/docs/curl-config.1 b/libs/libcurl/docs/curl-config.1
new file mode 100644
index 0000000000..14a9d2ba87
--- /dev/null
+++ b/libs/libcurl/docs/curl-config.1
@@ -0,0 +1,98 @@
+.\" **************************************************************************
+.\" * _ _ ____ _
+.\" * Project ___| | | | _ \| |
+.\" * / __| | | | |_) | |
+.\" * | (__| |_| | _ <| |___
+.\" * \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 1998 - 2012, 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.
+.\" *
+.\" **************************************************************************
+.\"
+.TH curl-config 1 "25 Oct 2007" "Curl 7.17.1" "curl-config manual"
+.SH NAME
+curl-config \- Get information about a libcurl installation
+.SH SYNOPSIS
+.B curl-config [options]
+.SH DESCRIPTION
+.B curl-config
+displays information about the curl and libcurl installation.
+.SH OPTIONS
+.IP "--ca"
+Displays the built-in path to the CA cert bundle this libcurl uses.
+.IP "--cc"
+Displays the compiler used to build libcurl.
+.IP "--cflags"
+Set of compiler options (CFLAGS) to use when compiling files that use
+libcurl. Currently that is only the include path to the curl include files.
+.IP "--checkfor [version]"
+Specify the oldest possible libcurl version string you want, and this
+script will return 0 if the current installation is new enough or it
+returns 1 and outputs a text saying that the current version is not new
+enough. (Added in 7.15.4)
+.IP "--configure"
+Displays the arguments given to configure when building curl.
+.IP "--feature"
+Lists what particular main features the installed libcurl was built with. At
+the time of writing, this list may include SSL, KRB4 or IPv6. Do not assume
+any particular order. The keywords will be separated by newlines. There may be
+none, one, or several keywords in the list.
+.IP "--help"
+Displays the available options.
+.IP "--libs"
+Shows the complete set of libs and other linker options you will need in order
+to link your application with libcurl.
+.IP "--prefix"
+This is the prefix used when libcurl was installed. Libcurl is then installed
+in $prefix/lib and its header files are installed in $prefix/include and so
+on. The prefix is set with "configure --prefix".
+.IP "--protocols"
+Lists what particular protocols the installed libcurl was built to support. At
+the time of writing, this list may include HTTP, HTTPS, FTP, FTPS, FILE,
+TELNET, LDAP, DICT. Do not assume any particular order. The protocols will
+be listed using uppercase and are separated by newlines. There may be none,
+one, or several protocols in the list. (Added in 7.13.0)
+.IP "--static-libs"
+Shows the complete set of libs and other linker options you will need in order
+to link your application with libcurl statically. (Added in 7.17.1)
+.IP "--version"
+Outputs version information about the installed libcurl.
+.IP "--vernum"
+Outputs version information about the installed libcurl, in numerical mode.
+This outputs the version number, in hexadecimal, with 8 bits for each part;
+major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl
+12.13.14 would appear as 0c0d0e... Note that the initial zero might be
+omitted. (This option was broken in the 7.15.0 release.)
+.SH "EXAMPLES"
+What linker options do I need when I link with libcurl?
+
+ $ curl-config --libs
+
+What compiler options do I need when I compile using libcurl functions?
+
+ $ curl-config --cflags
+
+How do I know if libcurl was built with SSL support?
+
+ $ curl-config --feature | grep SSL
+
+What's the installed libcurl version?
+
+ $ curl-config --version
+
+How do I build a single file with a one-line command?
+
+ $ `curl-config --cc --cflags` -o example example.c `curl-config --libs`
+.SH "SEE ALSO"
+.BR curl (1)
diff --git a/libs/libcurl/docs/curl-config.html b/libs/libcurl/docs/curl-config.html
new file mode 100644
index 0000000000..1563d548b9
--- /dev/null
+++ b/libs/libcurl/docs/curl-config.html
@@ -0,0 +1,91 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<title>curl-config man page</title>
+<meta name="generator" content="roffit">
+<STYLE type="text/css">
+P.level0 {
+ padding-left: 2em;
+}
+
+P.level1 {
+ padding-left: 4em;
+}
+
+P.level2 {
+ padding-left: 6em;
+}
+
+span.emphasis {
+ font-style: italic;
+}
+
+span.bold {
+ font-weight: bold;
+}
+
+span.manpage {
+ font-weight: bold;
+}
+
+h2.nroffsh {
+ background-color: #e0e0e0;
+}
+
+span.nroffip {
+ font-weight: bold;
+ font-size: 120%;
+ font-family: monospace;
+}
+
+p.roffit {
+ text-align: center;
+ font-size: 80%;
+}
+</STYLE>
+</head><body>
+
+<p class="level0"><a name="NAME"></a><h2 class="nroffsh">NAME</h2>
+<p class="level0">curl-config - Get information about a libcurl installation <a name="SYNOPSIS"></a><h2 class="nroffsh">SYNOPSIS</h2>
+<p class="level0"><span Class="bold">curl-config [options]</span> <a name="DESCRIPTION"></a><h2 class="nroffsh">DESCRIPTION</h2>
+<p class="level0"><span Class="bold">curl-config</span> displays information about the curl and libcurl installation. <a name="OPTIONS"></a><h2 class="nroffsh">OPTIONS</h2>
+<p class="level0">
+<p class="level0"><a name="--ca"></a><span class="nroffip">--ca</span>
+<p class="level1">Displays the built-in path to the CA cert bundle this libcurl uses.
+<p class="level0"><a name="--cc"></a><span class="nroffip">--cc</span>
+<p class="level1">Displays the compiler used to build libcurl.
+<p class="level0"><a name="--cflags"></a><span class="nroffip">--cflags</span>
+<p class="level1">Set of compiler options (CFLAGS) to use when compiling files that use libcurl. Currently that is only the include path to the curl include files.
+<p class="level0"><a name="--checkfor"></a><span class="nroffip">--checkfor [version]</span>
+<p class="level1">Specify the oldest possible libcurl version string you want, and this script will return 0 if the current installation is new enough or it returns 1 and outputs a text saying that the current version is not new enough. (Added in 7.15.4)
+<p class="level0"><a name="--configure"></a><span class="nroffip">--configure</span>
+<p class="level1">Displays the arguments given to configure when building curl.
+<p class="level0"><a name="--feature"></a><span class="nroffip">--feature</span>
+<p class="level1">Lists what particular main features the installed libcurl was built with. At the time of writing, this list may include SSL, KRB4 or IPv6. Do not assume any particular order. The keywords will be separated by newlines. There may be none, one, or several keywords in the list.
+<p class="level0"><a name="--help"></a><span class="nroffip">--help</span>
+<p class="level1">Displays the available options.
+<p class="level0"><a name="--libs"></a><span class="nroffip">--libs</span>
+<p class="level1">Shows the complete set of libs and other linker options you will need in order to link your application with libcurl.
+<p class="level0"><a name="--prefix"></a><span class="nroffip">--prefix</span>
+<p class="level1">This is the prefix used when libcurl was installed. Libcurl is then installed in $prefix/lib and its header files are installed in $prefix/include and so on. The prefix is set with "configure --prefix".
+<p class="level0"><a name="--protocols"></a><span class="nroffip">--protocols</span>
+<p class="level1">Lists what particular protocols the installed libcurl was built to support. At the time of writing, this list may include HTTP, HTTPS, FTP, FTPS, FILE, TELNET, LDAP, DICT. Do not assume any particular order. The protocols will be listed using uppercase and are separated by newlines. There may be none, one, or several protocols in the list. (Added in 7.13.0)
+<p class="level0"><a name="--static-libs"></a><span class="nroffip">--static-libs</span>
+<p class="level1">Shows the complete set of libs and other linker options you will need in order to link your application with libcurl statically. (Added in 7.17.1)
+<p class="level0"><a name="--version"></a><span class="nroffip">--version</span>
+<p class="level1">Outputs version information about the installed libcurl.
+<p class="level0"><a name="--vernum"></a><span class="nroffip">--vernum</span>
+<p class="level1">Outputs version information about the installed libcurl, in numerical mode. This outputs the version number, in hexadecimal, with 8 bits for each part; major, minor, patch. So that libcurl 7.7.4 would appear as 070704 and libcurl 12.13.14 would appear as 0c0d0e... Note that the initial zero might be omitted. (This option was broken in the 7.15.0 release.) <a name="EXAMPLES"></a><h2 class="nroffsh">EXAMPLES</h2>
+<p class="level0">What linker options do I need when I link with libcurl?
+<p class="level0">&nbsp; $ curl-config --libs
+<p class="level0">What compiler options do I need when I compile using libcurl functions?
+<p class="level0">&nbsp; $ curl-config --cflags
+<p class="level0">How do I know if libcurl was built with SSL support?
+<p class="level0">&nbsp; $ curl-config --feature | grep SSL
+<p class="level0">What's the installed libcurl version?
+<p class="level0">&nbsp; $ curl-config --version
+<p class="level0">How do I build a single file with a one-line command?
+<p class="level0">&nbsp; $ `curl-config --cc --cflags` -o example example.c `curl-config --libs` <a name="SEE"></a><h2 class="nroffsh">SEE ALSO</h2>
+<p class="level0"><span Class="manpage">curl (1)</span> <p class="roffit">
+ This HTML page was made with <a href="http://daniel.haxx.se/projects/roffit/">roffit</a>.
+</body></html>
diff --git a/libs/libcurl/docs/curl-config.pdf b/libs/libcurl/docs/curl-config.pdf
new file mode 100644
index 0000000000..0d0d994246
--- /dev/null
+++ b/libs/libcurl/docs/curl-config.pdf
Binary files differ
diff --git a/libs/libcurl/docs/curl.1 b/libs/libcurl/docs/curl.1
new file mode 100644
index 0000000000..30ef4ccf6f
--- /dev/null
+++ b/libs/libcurl/docs/curl.1
@@ -0,0 +1,2070 @@
+.\" **************************************************************************
+.\" * _ _ ____ _
+.\" * 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.
+.\" *
+.\" **************************************************************************
+.\"
+.TH curl 1 "27 July 2012" "Curl 7.27.0" "Curl Manual"
+.SH NAME
+curl \- transfer a URL
+.SH SYNOPSIS
+.B curl [options]
+.I [URL...]
+.SH DESCRIPTION
+.B curl
+is a tool to transfer data from or to a server, using one of the supported
+protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP,
+LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP). The
+command is designed to work without user interaction.
+
+curl offers a busload of useful tricks like proxy support, user
+authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer
+resume, Metalink, and more. As you will see below, the number of features will
+make your head spin!
+
+curl is powered by libcurl for all transfer-related features. See
+.BR libcurl (3)
+for details.
+.SH URL
+The URL syntax is protocol-dependent. You'll find a detailed description in
+RFC 3986.
+
+You can specify multiple URLs or parts of URLs by writing part sets within
+braces as in:
+
+ http://site.{one,two,three}.com
+
+or you can get sequences of alphanumeric series by using [] as in:
+
+ ftp://ftp.numericals.com/file[1-100].txt
+ ftp://ftp.numericals.com/file[001-100].txt (with leading zeros)
+ ftp://ftp.letters.com/file[a-z].txt
+
+Nested sequences are not supported, but you can use several ones next to each
+other:
+
+ http://any.org/archive[1996-1999]/vol[1-4]/part{a,b,c}.html
+
+You can specify any amount of URLs on the command line. They will be fetched
+in a sequential manner in the specified order.
+
+You can specify a step counter for the ranges to get every Nth number or
+letter:
+
+ http://www.numericals.com/file[1-100:10].txt
+ http://www.letters.com/file[a-z:2].txt
+
+If you specify URL without protocol:// prefix, curl will attempt to guess what
+protocol you might want. It will then default to HTTP but try other protocols
+based on often-used host name prefixes. For example, for host names starting
+with "ftp." curl will assume you want to speak FTP.
+
+curl will do its best to use what you pass to it as a URL. It is not trying to
+validate it as a syntactically correct URL by any means but is instead
+\fBvery\fP liberal with what it accepts.
+
+curl will attempt to re-use connections for multiple file transfers, so that
+getting many files from the same server will not do multiple connects /
+handshakes. This improves speed. Of course this is only done on files
+specified on a single command line and cannot be used between separate curl
+invokes.
+.SH "PROGRESS METER"
+curl normally displays a progress meter during operations, indicating the
+amount of transferred data, transfer speeds and estimated time left, etc.
+
+curl displays this data to the terminal by default, so if you invoke curl to
+do an operation and it is about to write data to the terminal, it
+\fIdisables\fP the progress meter as otherwise it would mess up the output
+mixing progress meter and response data.
+
+If you want a progress meter for HTTP POST or PUT requests, you need to
+redirect the response output to a file, using shell redirect (>), -o [file] or
+similar.
+
+It is not the same case for FTP upload as that operation does not spit out
+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
+the --option version of them. (This concept with --no options was added in
+7.19.0. Previously most options were toggled on/off on repeated use of the
+same command line option.)
+.IP "-#, --progress-bar"
+Make curl display progress as a simple progress bar instead of the standard,
+more informational, meter.
+.IP "-0, --http1.0"
+(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.
+.IP "-2, --sslv2"
+(SSL)
+Forces curl to use SSL version 2 when negotiating with a remote SSL server.
+.IP "-3, --sslv3"
+(SSL)
+Forces curl to use SSL version 3 when negotiating with a remote SSL server.
+.IP "-4, --ipv4"
+If curl is capable of resolving an address to multiple IP versions (which it
+is if it is IPv6-capable), this option tells curl to resolve names to IPv4
+addresses only.
+.IP "-6, --ipv6"
+If curl is capable of resolving an address to multiple IP versions (which it
+is if it is IPv6-capable), this option tells curl to resolve names to IPv6
+addresses only.
+.IP "-a, --append"
+(FTP/SFTP) When used in an upload, this will tell curl to append to the target
+file instead of overwriting it. If the file doesn't exist, it will be created.
+Note that this flag is ignored by some SSH servers (including OpenSSH).
+.IP "-A, --user-agent <agent string>"
+(HTTP) Specify the User-Agent string to send to the HTTP server. Some badly
+done CGIs fail if this field isn't set to "Mozilla/4.0". To encode blanks in
+the string, surround the string with single quote marks. This can also be set
+with the \fI-H, --header\fP option of course.
+
+If this option is used several times, the last one will be used.
+.IP "--anyauth"
+(HTTP) Tells curl to figure out authentication method by itself, and use the
+most secure one the remote site claims to support. This is done by first
+doing a request and checking the response-headers, thus possibly inducing an
+extra network round-trip. This is used instead of setting a specific
+authentication method, which you can do with \fI--basic\fP, \fI--digest\fP,
+\fI--ntlm\fP, and \fI--negotiate\fP.
+
+Note that using --anyauth is not recommended if you do uploads from stdin,
+since it may require data to be sent twice and then the client must be able to
+rewind. If the need should arise when uploading from stdin, the upload
+operation will fail.
+.IP "-b, --cookie <name=data>"
+(HTTP)
+Pass the data to the HTTP server as a cookie. It is supposedly the
+data previously received from the server in a "Set-Cookie:" line.
+The data should be in the format "NAME1=VALUE1; NAME2=VALUE2".
+
+If no '=' symbol is used in the line, it is treated as a filename to use to
+read previously stored cookie lines from, which should be used in this session
+if they match. Using this method also activates the "cookie parser" which will
+make curl record incoming cookies too, which may be handy if you're using this
+in combination with the \fI-L, --location\fP option. The file format of the
+file to read cookies from should be plain HTTP headers or the Netscape/Mozilla
+cookie file format.
+
+\fBNOTE\fP that the file specified with \fI-b, --cookie\fP is only used as
+input. No cookies will be stored in the file. To store cookies, use the
+\fI-c, --cookie-jar\fP option or you could even save the HTTP headers to a file
+using \fI-D, --dump-header\fP!
+
+If this option is used several times, the last one will be used.
+.IP "-B, --use-ascii"
+(FTP/LDAP) Enable ASCII transfer. For FTP, this can also be
+enforced by using an URL that ends with ";type=A". This option causes data
+sent to stdout to be in text mode for win32 systems.
+.IP "--basic"
+(HTTP) Tells curl to use HTTP Basic authentication. This is the default and
+this option is usually pointless, unless you use it to override a previously
+set option that sets a different authentication method (such as \fI--ntlm\fP,
+\fI--digest\fP, or \fI--negotiate\fP).
+.IP "-c, --cookie-jar <file name>"
+(HTTP) Specify to which file you want curl to write all cookies after a
+completed operation. Curl writes all cookies previously read from a specified
+file as well as all cookies received from remote server(s). If no cookies are
+known, no file will be written. The file will be written using the Netscape
+cookie file format. If you set the file name to a single dash, "-", the
+cookies will be written to stdout.
+
+This command line option will activate the cookie engine that makes curl
+record and use cookies. Another way to activate it is to use the \fI-b,
+--cookie\fP option.
+
+If the cookie jar can't be created or written to, the whole curl operation
+won't fail or even report an error clearly. Using -v will get a warning
+displayed, but that is the only visible feedback you get about this possibly
+lethal situation.
+
+If this option is used several times, the last specified file name will be
+used.
+.IP "-C, --continue-at <offset>"
+Continue/Resume a previous file transfer at the given offset. The given offset
+is the exact number of bytes that will be skipped, counting from the beginning
+of the source file before it is transferred to the destination. If used with
+uploads, the FTP server command SIZE will not be used by curl.
+
+Use "-C -" to tell curl to automatically find out where/how to resume the
+transfer. It then uses the given output/input files to figure that out.
+
+If this option is used several times, the last one will be used.
+.IP "--ciphers <list of ciphers>"
+(SSL) Specifies which ciphers to use in the connection. The list of ciphers
+must specify valid ciphers. Read up on SSL cipher list details on this URL:
+\fIhttp://www.openssl.org/docs/apps/ciphers.html\fP
+
+NSS ciphers are done differently than OpenSSL and GnuTLS. The full list of NSS
+ciphers is in the NSSCipherSuite entry at this URL:
+\fIhttp://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html#Directives\fP
+
+If this option is used several times, the last one will be used.
+.IP "--compressed"
+(HTTP) Request a compressed response using one of the algorithms curl
+supports, and save the uncompressed document. If this option is used and the
+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. 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"
+When used in conjunction with the \fI-o\fP option, curl will create the
+necessary local directory hierarchy as needed. This option creates the dirs
+mentioned with the \fI-o\fP option, nothing else. If the \fI-o\fP file name
+uses no dir or if the dirs it mentions already exist, no dir will be created.
+
+To create remote directories when using FTP or SFTP, try
+\fI--ftp-create-dirs\fP.
+.IP "--crlf"
+(FTP) Convert LF to CRLF in upload. Useful for MVS (OS/390).
+.IP "--crlfile <file>"
+(HTTPS/FTPS) Provide a file using PEM format with a Certificate Revocation
+List that may specify peer certificates that are to be considered revoked.
+
+If this option is used several times, the last one will be used.
+
+(Added in 7.19.7)
+.IP "-d, --data <data>"
+(HTTP) Sends the specified data in a POST request to the HTTP server, in the
+same way that a browser does when a user has filled in an HTML form and
+presses the submit button. This will cause curl to pass the data to the server
+using the content-type application/x-www-form-urlencoded. Compare to
+\fI-F, --form\fP.
+
+\fI-d, --data\fP is the same as \fI--data-ascii\fP. To post data purely binary,
+you should instead use the \fI--data-binary\fP option. To URL-encode the value
+of a form field you may use \fI--data-urlencode\fP.
+
+If any of these options is used more than once on the same command line, the
+data pieces specified will be merged together with a separating
+&-symbol. Thus, using '-d name=daniel -d skill=lousy' would generate a post
+chunk that looks like \&'name=daniel&skill=lousy'.
+
+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\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.
+
+This option is handy to use when you want to store the headers that an HTTP
+site sends to you. Cookies from the headers could then be read in a second
+curl invocation by using the \fI-b, --cookie\fP option! The
+\fI-c, --cookie-jar\fP option is however a better way to store cookies.
+
+When used in FTP, the FTP server response lines are considered being "headers"
+and thus are saved there.
+
+If this option is used several times, the last one will be used.
+
+.IP "--data-ascii <data>"
+See \fI-d, --data\fP.
+.IP "--data-binary <data>"
+(HTTP) This posts data exactly as specified with no extra processing
+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
+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.
+.IP "--data-urlencode <data>"
+(HTTP) This posts data, similar to the other --data options with the exception
+that this performs URL-encoding. (Added in 7.18.0)
+
+To be CGI-compliant, the <data> part should begin with a \fIname\fP followed
+by a separator and a content specification. The <data> part can be passed to
+curl using one of the following syntaxes:
+.RS
+.IP "content"
+This will make curl URL-encode the content and pass that on. Just be careful
+so that the content doesn't contain any = or @ symbols, as that will then make
+the syntax match one of the other cases below!
+.IP "=content"
+This will make curl URL-encode the content and pass that on. The preceding =
+symbol is not included in the data.
+.IP "name=content"
+This will make curl URL-encode the content part and pass that on. Note that
+the name part is expected to be URL-encoded already.
+.IP "@filename"
+This will make curl load data from the given file (including any newlines),
+URL-encode that data and pass it on in the POST.
+.IP "name@filename"
+This will make curl load data from the given file (including any newlines),
+URL-encode that data and pass it on in the POST. The name part gets an equal
+sign appended, resulting in \fIname=urlencoded-file-content\fP. Note that the
+name is expected to be URL-encoded already.
+.RE
+.IP "--delegation LEVEL"
+Set \fILEVEL\fP to tell the server what it is allowed to delegate when it
+comes to user credentials. Used with GSS/kerberos.
+.RS
+.IP "none"
+Don't allow any delegation.
+.IP "policy"
+Delegates if and only if the OK-AS-DELEGATE flag is set in the Kerberos
+service ticket, which is a matter of realm policy.
+.IP "always"
+Unconditionally allow the server to delegate.
+.RE
+.IP "--digest"
+(HTTP) Enables HTTP Digest authentication. This is an authentication scheme
+that prevents the password from being sent over the wire in clear text. Use
+this in combination with the normal \fI-u, --user\fP option to set user name
+and password. See also \fI--ntlm\fP, \fI--negotiate\fP and \fI--anyauth\fP for
+related options.
+
+If this option is used several times, only the first one is used.
+.IP "--disable-eprt"
+(FTP) Tell curl to disable the use of the EPRT and LPRT commands when doing
+active FTP transfers. Curl will normally always first attempt to use EPRT,
+then LPRT before using PORT, but with this option, it will use PORT right
+away. EPRT and LPRT are extensions to the original FTP protocol, and may not
+work on all servers, but they enable more functionality in a better way than
+the traditional PORT command.
+
+\fB--eprt\fP can be used to explicitly enable EPRT again and \fB--no-eprt\fP
+is an alias for \fB--disable-eprt\fP.
+
+Disabling EPRT only changes the active behavior. If you want to switch to
+passive mode you need to not use \fI-P, --ftp-port\fP or force it with
+\fI--ftp-pasv\fP.
+.IP "--disable-epsv"
+(FTP) Tell curl to disable the use of the EPSV command when doing passive FTP
+transfers. Curl will normally always first attempt to use EPSV before PASV,
+but with this option, it will not try using EPSV.
+
+\fB--epsv\fP can be used to explicitly enable EPSV again and \fB--no-epsv\fP
+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
+\fI-L, --location\fP you can append ";auto" to the --referer URL to make curl
+automatically set the previous URL when it follows a Location: header. The
+\&";auto" string can be used alone, even if you don't set an initial --referer.
+
+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 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.
+
+If curl is built against the NSS SSL library then this option can tell
+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. 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>"
+Select the OpenSSL crypto engine to use for cipher
+operations. Use \fI--engine list\fP to print a list of build-time supported
+engines. Note that not all (or none) of the engines may be available at
+run-time.
+.IP "--environment"
+(RISC OS ONLY) Sets a range of environment variables, using the names the
+\fI-w\fP option supports, to allow easier extraction of useful information
+after having run curl.
+.IP "--egd-file <file>"
+(SSL) Specify the path name to the Entropy Gathering Daemon socket. The socket
+is used to seed the random engine for SSL connections. See also the
+\fI--random-file\fP option.
+.IP "--cert-type <type>"
+(SSL) Tells curl what certificate type the provided certificate is in. PEM,
+DER and ENG are recognized types. If not specified, PEM is assumed.
+
+If this option is used several times, the last one will be used.
+.IP "--cacert <CA certificate>"
+(SSL) Tells curl to use the specified certificate file to verify the peer. The
+file may contain multiple CA certificates. The certificate(s) must be in PEM
+format. Normally curl is built to use a default file for this, so this option
+is typically used to alter that default file.
+
+curl recognizes the environment variable named 'CURL_CA_BUNDLE' if it is
+set, and uses the given path as a path to a CA cert bundle. This option
+overrides that variable.
+
+The windows version of curl will automatically look for a CA certs file named
+\'curl-ca-bundle.crt\', either in the same directory as curl.exe, or in the
+Current Working Directory, or in any folder along your PATH.
+
+If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module
+(libnsspem.so) needs to be available for this option to work properly.
+
+If this option is used several times, the last one will be used.
+.IP "--capath <CA certificate directory>"
+(SSL) Tells curl to use the specified certificate directory to verify the
+peer. Multiple paths can be provided by separating them with ":" (e.g.
+\&"path1:path2:path3"). The certificates must be in PEM format, and if curl is
+built against OpenSSL, the directory must have been processed using the
+c_rehash utility supplied with OpenSSL. Using \fI--capath\fP can allow
+OpenSSL-powered curl to make SSL-connections much more efficiently than using
+\fI--cacert\fP if the \fI--cacert\fP file contains many CA certificates.
+
+If this option is set, the default capath value will be ignored, and if it is
+used several times, the last one will be used.
+.IP "-f, --fail"
+(HTTP) Fail silently (no output at all) on server errors. This is mostly done
+to better enable scripts etc to better deal with failed attempts. In
+normal cases when an HTTP server fails to deliver a document, it returns an
+HTML document stating so (which often also describes why and more). This flag
+will prevent curl from outputting that and return error 22.
+
+This method is not fail-safe and there are occasions where non-successful
+response codes will slip through, especially when authentication is involved
+(response codes 401 and 407).
+.IP "-F, --form <name=content>"
+(HTTP) This lets curl emulate a filled-in form in which a user has pressed the
+submit button. This causes curl to POST data using the Content-Type
+multipart/form-data according to RFC 2388. This enables uploading of binary
+files etc. To force the 'content' part to be a file, prefix the file name
+with an @ sign. To just get the content part from a file, prefix the file name
+with the symbol <. The difference between @ and < is then that @ makes a file
+get attached in the post as a file upload, while the < makes a text field and
+just get the contents for that text field from a file.
+
+Example, to send your password file to the server, where
+\&'password' is the name of the form-field to which /etc/passwd will be the
+input:
+
+\fBcurl\fP -F password=@/etc/passwd www.mypasswords.com
+
+To read content from stdin instead of a file, use - as the filename. This goes
+for both @ and < constructs.
+
+You can also tell curl what Content-Type to use by using 'type=', in a manner
+similar to:
+
+\fBcurl\fP -F "web=@index.html;type=text/html" url.com
+
+or
+
+\fBcurl\fP -F "name=daniel;type=text/foo" url.com
+
+You can also explicitly change the name field of a file upload part by setting
+filename=, like this:
+
+\fBcurl\fP -F "file=@localfile;filename=nameinpost" url.com
+
+If filename/path contains ',' or ';', it must be quoted by double-quotes like:
+
+\fBcurl\fP -F "file=@\\"localfile\\";filename=\\"nameinpost\\"" url.com
+
+or
+
+\fBcurl\fP -F 'file=@"localfile";filename="nameinpost"' url.com
+
+Note that if a filename/path is quoted by double-quotes, any double-quote
+or backslash within the filename must be escaped by backslash.
+
+See further examples and details in the MANUAL.
+
+This option can be used multiple times.
+.IP "--ftp-account [data]"
+(FTP) When an FTP server asks for "account data" after user name and password
+has been provided, this data is sent off using the ACCT command. (Added in
+7.13.0)
+
+If this option is used several times, the last one will be used.
+.IP "--ftp-alternative-to-user <command>"
+(FTP) If authenticating with the USER and PASS commands fails, send this
+command. When connecting to Tumbleweed's Secure Transport server over FTPS
+using a client certificate, using "SITE AUTH" will tell the server to retrieve
+the username from the certificate. (Added in 7.15.5)
+.IP "--ftp-create-dirs"
+(FTP/SFTP) When an FTP or SFTP URL/operation uses a path that doesn't
+currently exist on the server, the standard behavior of curl is to
+fail. Using this option, curl will instead attempt to create missing
+directories.
+.IP "--ftp-method [method]"
+(FTP) Control what method curl should use to reach a file on an FTP(S)
+server. The method argument should be one of the following alternatives:
+.RS
+.IP multicwd
+curl does a single CWD operation for each path part in the given URL. For deep
+hierarchies this means very many commands. This is how RFC 1738 says it should
+be done. This is the default but the slowest behavior.
+.IP nocwd
+curl does no CWD at all. curl will do SIZE, RETR, STOR etc and give a full
+path to the server for all these commands. This is the fastest behavior.
+.IP singlecwd
+curl does one CWD with the full target directory and then operates on the file
+\&"normally" (like in the multicwd case). This is somewhat more standards
+compliant than 'nocwd' but without the full penalty of 'multicwd'.
+.RE
+(Added in 7.15.1)
+.IP "--ftp-pasv"
+(FTP) Use passive mode for the data connection. Passive is the internal default
+behavior, but using this option can be used to override a previous
+\fI-P/-ftp-port\fP option. (Added in 7.11.0)
+
+If this option is used several times, only the first one is used. Undoing an
+enforced passive really isn't doable but you must then instead enforce the
+correct \fI-P, --ftp-port\fP again.
+
+Passive mode means that curl will try the EPSV command first and then PASV,
+unless \fI--disable-epsv\fP is used.
+.IP "--ftp-skip-pasv-ip"
+(FTP) Tell curl to not use the IP address the server suggests in its response
+to curl's PASV command when curl connects the data connection. Instead curl
+will re-use the same IP address it already uses for the control
+connection. (Added in 7.14.2)
+
+This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+.IP "--ftp-pret"
+(FTP) Tell curl to send a PRET command before PASV (and EPSV). Certain
+FTP servers, mainly drftpd, require this non-standard command for
+directory listings as well as up and downloads in PASV mode.
+(Added in 7.20.x)
+.IP "--ftp-ssl-ccc"
+(FTP) Use CCC (Clear Command Channel)
+Shuts down the SSL/TLS layer after authenticating. The rest of the
+control channel communication will be unencrypted. This allows
+NAT routers to follow the FTP transaction. The default mode is
+passive. See \fI--ftp-ssl-ccc-mode\fP for other modes.
+(Added in 7.16.1)
+.IP "--ftp-ssl-ccc-mode [active/passive]"
+(FTP) Use CCC (Clear Command Channel)
+Sets the CCC mode. The passive mode will not initiate the shutdown, but
+instead wait for the server to do it, and will not reply to the
+shutdown from the server. The active mode initiates the shutdown and
+waits for a reply from the server.
+(Added in 7.16.2)
+.IP "--ftp-ssl-control"
+(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure
+authentication, but non-encrypted data transfers for efficiency. Fails the
+transfer if the server doesn't support SSL/TLS. (Added in 7.16.0)
+that can still be used but will be removed in a future version.
+.IP "--form-string <name=string>"
+(HTTP) Similar to \fI--form\fP except that the value string for the named
+parameter is used literally. Leading \&'@' and \&'<' characters, and the
+\&';type=' string in the value have no special meaning. Use this in preference
+to \fI--form\fP if there's any possibility that the string value may
+accidentally trigger the \&'@' or \&'<' features of \fI--form\fP.
+.IP "-g, --globoff"
+This option switches off the "URL globbing parser". When you set this option,
+you can specify URLs that contain the letters {}[] without having them being
+interpreted by curl itself. Note that these letters are not normal legal URL
+contents but they should be encoded according to the URI standard.
+.IP "-G, --get"
+When used, this option will make all data specified with \fI-d, --data\fP or
+\fI--data-binary\fP to be used in an HTTP GET request instead of the POST
+request that otherwise would be used. The data will be appended to the URL
+with a '?' separator.
+
+If used in combination with -I, the POST data will instead be appended to the
+URL with a HEAD request.
+
+If this option is used several times, only the first one is used. This is
+because undoing a GET doesn't make sense, but you should then instead enforce
+the alternative method you prefer.
+.IP "-H, --header <header>"
+(HTTP) Extra header to use when getting a web page. You may specify any number
+of extra headers. Note that if you should add a custom header that has the
+same name as one of the internal ones curl would use, your externally set
+header will be used instead of the internal one. This allows you to make even
+trickier stuff than curl would normally do. You should not replace internally
+set headers without knowing perfectly well what you're doing. Remove an
+internal header by giving a replacement without content on the right side of
+the colon, as in: -H \&"Host:". If you send the custom header with no-value
+then its header must be terminated with a semicolon, such as \-H
+\&"X-Custom-Header;" to send "X-Custom-Header:".
+
+curl will make sure that each header you add/replace is sent with the proper
+end-of-line marker, you should thus \fBnot\fP add that as a part of the header
+content: do not add newlines or carriage returns, they will only mess things up
+for you.
+
+See also the \fI-A, --user-agent\fP and \fI-e, --referer\fP options.
+
+This option can be used multiple times to add/replace/remove multiple headers.
+.IP "--hostpubmd5 <md5>"
+(SCP/SFTP) Pass a string containing 32 hexadecimal digits. The string should
+be the 128 bit MD5 checksum of the remote host's public key, curl will refuse
+the connection with the host unless the md5sums match. (Added in 7.17.1)
+.IP "--ignore-content-length"
+(HTTP)
+Ignore the Content-Length header. This is particularly useful for servers
+running Apache 1.x, which will report incorrect Content-Length for files
+larger than 2 gigabytes.
+.IP "-i, --include"
+(HTTP) Include the HTTP-header in the output. The HTTP-header includes things
+like server-name, date of the document, HTTP-version and more...
+.IP "-I, --head"
+(HTTP/FTP/FILE)
+Fetch the HTTP-header only! HTTP-servers feature the command HEAD
+which this uses to get nothing but the header of a document. When used
+on an FTP or FILE file, curl displays the file size and last modification
+time only.
+.IP "--interface <name>"
+Perform an operation using a specified interface. You can enter interface
+name, IP address or host name. An example could look like:
+
+ curl --interface eth0:1 http://www.netscape.com/
+
+If this option is used several times, the last one will be used.
+.IP "-j, --junk-session-cookies"
+(HTTP) When curl is told to read cookies from a given file, this option will
+make it discard all "session cookies". This will basically have the same effect
+as if a new session is started. Typical browsers always discard session
+cookies when they're closed down.
+.IP "-J, --remote-header-name"
+(HTTP) This option tells the \fI-O, --remote-name\fP option to use the
+server-specified Content-Disposition filename instead of extracting a filename
+from the URL.
+.IP "-k, --insecure"
+(SSL) This option explicitly allows curl to perform "insecure" SSL connections
+and transfers. All SSL connections are attempted to be made secure by using
+the CA certificate bundle installed by default. This makes all connections
+considered "insecure" fail unless \fI-k, --insecure\fP is used.
+
+See this online resource for further details:
+\fBhttp://curl.haxx.se/docs/sslcerts.html\fP
+.IP "-K, --config <config file>"
+Specify which config file to read curl arguments from. The config file is a
+text file in which command line arguments can be written which then will be
+used as if they were written on the actual command line. Options and their
+parameters must be specified on the same config file line, separated by
+whitespace, colon, the equals sign or any combination thereof (however,
+the preferred separator is the equals sign). If the parameter is to contain
+whitespace, the parameter must be enclosed within quotes. Within double
+quotes, the following escape sequences are available: \\\\, \\", \\t, \\n,
+\\r and \\v. A backslash preceding any other letter is ignored. If the
+first column of a config line is a '#' character, the rest of the line will be
+treated as a comment. Only write one option per physical line in the config
+file.
+
+Specify the filename to -K, --config as '-' to make curl read the file from
+stdin.
+
+Note that to be able to specify a URL in the config file, you need to specify
+it using the \fI--url\fP option, and not by simply writing the URL on its own
+line. So, it could look similar to this:
+
+url = "http://curl.haxx.se/docs/"
+
+Long option names can optionally be given in the config file without the
+initial double dashes.
+
+When curl is invoked, it always (unless \fI-q\fP is used) checks for a default
+config file and uses it if found. The default config file is checked for in
+the following places in this order:
+
+1) curl tries to find the "home dir": It first checks for the CURL_HOME and
+then the HOME environment variables. Failing that, it uses getpwuid() on
+UNIX-like systems (which returns the home dir given the current user in your
+system). On Windows, it then checks for the APPDATA variable, or as a last
+resort the '%USERPROFILE%\\Application Data'.
+
+2) On windows, if there is no _curlrc file in the home dir, it checks for one
+in the same dir the curl executable is placed. On UNIX-like systems, it will
+simply try to load .curlrc from the determined home dir.
+
+.nf
+# --- Example file ---
+# this is a comment
+url = "curl.haxx.se"
+output = "curlhere.html"
+user-agent = "superagent/1.0"
+
+# and fetch another URL too
+url = "curl.haxx.se/docs/manpage.html"
+-O
+referer = "http://nowhereatall.com/"
+# --- End of example file ---
+.fi
+
+This option can be used multiple times to load multiple config files.
+.IP "--keepalive-time <seconds>"
+This option sets the time a connection needs to remain idle before sending
+keepalive probes and the time between individual keepalive probes. It is
+currently effective on operating systems offering the TCP_KEEPIDLE and
+TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This
+option has no effect if \fI--no-keepalive\fP is used. (Added in 7.18.0)
+
+If this option is used several times, the last one will be used. If
+unspecified, the option defaults to 60 seconds.
+.IP "--key <key>"
+(SSL/SSH) Private key file name. Allows you to provide your private key in this
+separate file.
+
+If this option is used several times, the last one will be used.
+.IP "--key-type <type>"
+(SSL) Private key file type. Specify which type your \fI--key\fP provided
+private key is. DER, PEM, and ENG are supported. If not specified, PEM is
+assumed.
+
+If this option is used several times, the last one will be used.
+.IP "--krb <level>"
+(FTP) Enable Kerberos authentication and use. The level must be entered and
+should be one of 'clear', 'safe', 'confidential', or 'private'. Should you use
+a level that is not one of these, 'private' will instead be used.
+
+This option requires a library built with kerberos4 or GSSAPI
+(GSS-Negotiate) support. This is not very common. Use \fI-V, --version\fP to
+see if your curl supports it.
+
+If this option is used several times, the last one will be used.
+.IP "-l, --list-only"
+(FTP)
+When listing an FTP directory, this switch forces a name-only view.
+Especially useful if you want to machine-parse the contents of an FTP
+directory since the normal directory view doesn't use a standard look
+or format.
+
+This option causes an FTP NLST command to be sent. Some FTP servers
+list only files in their response to NLST; they do not include
+subdirectories and symbolic links.
+
+.IP "-L, --location"
+(HTTP/HTTPS) If the server reports that the requested page has moved to a
+different location (indicated with a Location: header and a 3XX response code),
+this option will make curl redo the request on the new place. If used together
+with \fI-i, --include\fP or \fI-I, --head\fP, headers from all requested pages
+will be shown. When authentication is used, curl only sends its credentials to
+the initial host. If a redirect takes curl to a different host, it won't be
+able to intercept the user+password. See also \fI--location-trusted\fP on how
+to change this. You can limit the amount of redirects to follow by using the
+\fI--max-redirs\fP option.
+
+When curl follows a redirect and the request is not a plain GET (for example
+POST or PUT), it will do the following request with a GET if the HTTP response
+was 301, 302, or 303. If the response code was any other 3xx code, curl will
+re-send the following request using the same unmodified method.
+.IP "--libcurl <file>"
+Append this option to any ordinary curl command line, and you will get a
+libcurl-using C source code written to the file that does the equivalent
+of what your command-line operation does!
+
+If this option is used several times, the last given file name will be
+used. (Added in 7.16.1)
+.IP "--limit-rate <speed>"
+Specify the maximum transfer rate you want curl to use. This feature is useful
+if you have a limited pipe and you'd like your transfer not to use your entire
+bandwidth.
+
+The given speed is measured in bytes/second, unless a suffix is appended.
+Appending 'k' or 'K' will count the number as kilobytes, 'm' or M' makes it
+megabytes, while 'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G.
+
+The given rate is the average speed counted during the entire transfer. It
+means that curl might use higher transfer speeds in short bursts, but over
+time it uses no more than the given rate.
+
+If you also use the \fI-Y, --speed-limit\fP option, that option will take
+precedence and might cripple the rate-limiting slightly, to help keeping the
+speed-limit logic working.
+
+If this option is used several times, the last one will be used.
+.IP "--local-port <num>[-num]"
+Set a preferred number or range of local port numbers to use for the
+connection(s). Note that port numbers by nature are a scarce resource that
+will be busy at times so setting this range to something too narrow might
+cause unnecessary connection setup failures. (Added in 7.15.2)
+.IP "--location-trusted"
+(HTTP/HTTPS) Like \fI-L, --location\fP, but will allow sending the name +
+password to all hosts that the site may redirect to. This may or may not
+introduce a security breach if the site redirects you to a site to which
+you'll send your authentication info (which is plaintext in the case of HTTP
+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. 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>"
+(SMTP) Specify a single address. This will be used to specify the
+authentication address (identity) of a submitted message that is being relayed
+to another server.
+
+(Added in 7.25.0)
+.IP "--mail-from <address>"
+(SMTP) Specify a single address that the given mail should get sent from.
+
+(Added in 7.20.0)
+.IP "--max-filesize <bytes>"
+Specify the maximum size (in bytes) of a file to download. If the file
+requested is larger than this value, the transfer will not start and curl will
+return with exit code 63.
+
+\fBNOTE:\fP The file size is not always known prior to download, and for such
+files this option has no effect even if the file transfer ends up being larger
+than this given limit. This concerns both FTP and HTTP transfers.
+.IP "--mail-rcpt <address>"
+(SMTP) Specify a single address that the given mail should get sent to. This
+option can be used multiple times to specify many recipients.
+
+(Added in 7.20.0)
+.IP "--max-redirs <num>"
+Set maximum number of redirection-followings allowed. If \fI-L, --location\fP
+is used, this option can be used to prevent curl from following redirections
+\&"in absurdum". By default, the limit is set to 50 redirections. Set this
+option to -1 to make it limitless.
+
+If this option is used several times, the last one will be used.
+.IP "--metalink"
+This option can tell curl to parse and process a given URI as Metalink file
+(both version 3 and 4 (RFC 5854) are supported) and make use of the mirrors
+listed within for failover if there are errors (such as the file or server not
+being available). It will also verify the hash of the file after the download
+completes. The Metalink file itself is downloaded and processed in memory and
+not stored in the local file system.
+
+Example to use a remote Metalink file:
+
+\fBcurl\fP --metalink http://www.example.com/example.metalink
+
+To use a Metalink file in the local file system, use FILE protocol
+(file://):
+
+\fBcurl\fP --metalink file://example.metalink
+
+Please note that if FILE protocol is disabled, there is no way to use
+a local Metalink file at the time of this writing. Also note that if
+\fI--metalink\fP and \fI--include\fP are used together, \fI--include\fP will be
+ignored. This is because including headers in the response will break
+Metalink parser and if the headers are included in the file described
+in Metalink file, hash check will fail.
+
+(Added in 7.27.0, if built against the libmetalink library.)
+.IP "-n, --netrc"
+Makes curl scan the \fI.netrc\fP (\fI_netrc\fP on Windows) file in the user's
+home directory for login name and password. This is typically used for FTP on
+UNIX. If used with HTTP, curl will enable user authentication. See
+.BR netrc(4)
+or
+.BR ftp(1)
+for details on the file format. Curl will not complain if that file
+doesn't have the right permissions (it should not be either world- or
+group-readable). The environment variable "HOME" is used to find the home
+directory.
+
+A quick and very simple example of how to setup a \fI.netrc\fP to allow curl
+to FTP to the machine host.domain.com with user name \&'myself' and password
+\&'secret' should look similar to:
+
+.B "machine host.domain.com login myself password secret"
+.IP "-N, --no-buffer"
+Disables the buffering of the output stream. In normal work situations, curl
+will use a standard buffered output stream that will have the effect that it
+will output the data in chunks, not necessarily exactly when the data arrives.
+Using this option will disable that buffering.
+
+Note that this is the negated option name documented. You can thus use
+\fI--buffer\fP to enforce the buffering.
+.IP "--netrc-file"
+This option is similar to \fI--netrc\fP, except that you provide the path
+(absolute or relative) to the netrc file that Curl should use.
+You can only specify one netrc file per invocation. If several
+\fI--netrc-file\fP options are provided, only the \fBlast one\fP will be used.
+(Added in 7.21.5)
+
+This option overrides any use of \fI--netrc\fP as they are mutually exclusive.
+It will also abide by \fI--netrc-optional\fP if specified.
+
+.IP "--netrc-optional"
+Very similar to \fI--netrc\fP, but this option makes the .netrc usage
+\fBoptional\fP and not mandatory as the \fI--netrc\fP option does.
+
+.IP "--negotiate"
+(HTTP) Enables GSS-Negotiate authentication. The GSS-Negotiate method was
+designed by Microsoft and is used in their web applications. It is primarily
+meant as a support for Kerberos5 authentication but may be also used along
+with another authentication method. For more information see IETF draft
+draft-brezak-spnego-http-04.txt.
+
+If you want to enable Negotiate for your proxy authentication, then use
+\fI--proxy-negotiate\fP.
+
+This option requires a library built with GSSAPI support. This is
+not very common. Use \fI-V, --version\fP to see if your version supports
+GSS-Negotiate.
+
+When using this option, you must also provide a fake \fI-u, --user\fP option to
+activate the authentication code properly. Sending a '-u :' is enough as the
+user name and password from the \fI-u\fP option aren't actually used.
+
+If this option is used several times, only the first one is used.
+.IP "--no-keepalive"
+Disables the use of keepalive messages on the TCP connection, as by default
+curl enables them.
+
+Note that this is the negated option name documented. You can thus use
+\fI--keepalive\fP to enforce keepalive.
+.IP "--no-sessionid"
+(SSL) Disable curl's use of SSL session-ID caching. By default all transfers
+are done using the cache. Note that while nothing should ever get hurt by
+attempting to reuse SSL session-IDs, there seem to be broken SSL
+implementations in the wild that may require you to disable this in order for
+you to succeed. (Added in 7.16.0)
+
+Note that this is the negated option name documented. You can thus use
+\fI--sessionid\fP to enforce session-ID caching.
+.IP "--noproxy <no-proxy-list>"
+Comma-separated list of hosts which do not use a proxy, if one is specified.
+The only wildcard is a single * character, which matches all hosts, and
+effectively disables the proxy. Each name in this list is matched as either
+a domain which contains the hostname, or the hostname itself. For example,
+local.com would match local.com, local.com:80, and www.local.com, but not
+www.notlocal.com. (Added in 7.19.4).
+.IP "--ntlm"
+(HTTP) Enables NTLM authentication. The NTLM authentication method was
+designed by Microsoft and is used by IIS web servers. It is a proprietary
+protocol, reverse-engineered by clever people and implemented in curl based
+on their efforts. This kind of behavior should not be endorsed, you should
+encourage everyone who uses NTLM to switch to a public and documented
+authentication method instead, such as Digest.
+
+If you want to enable NTLM for your proxy authentication, then use
+\fI--proxy-ntlm\fP.
+
+This option requires a library built with SSL support. Use
+\fI-V, --version\fP to see if your curl supports NTLM.
+
+If this option is used several times, only the first one is used.
+.IP "-o, --output <file>"
+Write output to <file> instead of stdout. If you are using {} or [] to fetch
+multiple documents, you can use '#' followed by a number in the <file>
+specifier. That variable will be replaced with the current string for the URL
+being fetched. Like in:
+
+ curl http://{one,two}.site.com -o "file_#1.txt"
+
+or use several variables like:
+
+ curl http://{site,host}.host[1-5].com -o "#1_#2"
+
+You may use this option as many times as the number of URLs you have.
+
+See also the \fI--create-dirs\fP option to create the local directories
+dynamically. Specifying the output as '-' (a single dash) will force the
+output to be done to stdout.
+.IP "-O, --remote-name"
+Write output to a local file named like the remote file we get. (Only the file
+part of the remote file is used, the path is cut off.)
+
+The remote file name to use for saving is extracted from the given URL,
+nothing else.
+
+Consequentially, the file will be saved in the current working directory. If
+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
+do HTTP-like operations. The tunnel approach is made with the HTTP proxy
+CONNECT request and requires that the proxy allows direct connect to the
+remote port number curl wants to tunnel through to.
+.IP "-P, --ftp-port <address>"
+(FTP) Reverses the default initiator/listener roles when connecting with
+FTP. This switch makes curl use active mode. In practice, curl then tells the
+server to connect back to the client's specified address and port, while
+passive mode asks the server to setup an IP address and port for it to connect
+to. <address> should be one of:
+.RS
+.IP interface
+i.e "eth0" to specify which interface's IP address you want to use (Unix only)
+.IP "IP address"
+i.e "192.168.10.1" to specify the exact IP address
+.IP "host name"
+i.e "my.host.domain" to specify the machine
+.IP "-"
+make curl pick the same IP address that is already used for the control
+connection
+.RE
+
+If this option is used several times, the last one will be used. Disable the
+use of PORT with \fI--ftp-pasv\fP. Disable the attempt to use the EPRT command
+instead of PORT by using \fI--disable-eprt\fP. EPRT is really PORT++.
+
+Starting in 7.19.5, you can append \&":[start]-[end]\&" to the right of the
+address, to tell curl what TCP port range to use. That means you specify a
+port range, from a lower to a higher number. A single number works as well,
+but do note that it increases the risk of failure since the port may not be
+available.
+.IP "--pass <phrase>"
+(SSL/SSH) Passphrase for the private key
+
+If this option is used several times, the last one will be used.
+.IP "--post301"
+(HTTP) Tells curl to respect RFC 2616/10.3.2 and not convert POST requests
+into GET requests when following a 301 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.17.1)
+.IP "--post302"
+(HTTP) Tells curl to respect RFC 2616/10.3.2 and not convert POST requests
+into GET requests when following a 302 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.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
+name or 'all', optionally prefixed by zero or more modifiers. Available
+modifiers are:
+.RS
+.TP 3
+.B +
+Permit this protocol in addition to protocols already permitted (this is
+the default if no modifier is used).
+.TP
+.B -
+Deny this protocol, removing it from the list of protocols already permitted.
+.TP
+.B =
+Permit only this protocol (ignoring the list already permitted), though
+subject to later modification by subsequent entries in the comma separated
+list.
+.RE
+.IP
+For example:
+.RS
+.TP 15
+.B --proto -ftps
+uses the default protocols, but disables ftps
+.TP
+.B --proto -all,https,+http
+only enables http and https
+.TP
+.B --proto =http,https
+also only enables http and https
+.RE
+.IP
+Unknown protocols produce a warning. This allows scripts to safely rely on
+being able to disable potentially dangerous protocols, without relying upon
+support for that protocol being built into curl to avoid an error.
+
+This option can be used multiple times, in which case the effect is the same
+as concatenating the protocols into one instance of the option.
+
+(Added in 7.20.2)
+.IP "--proto-redir <protocols>"
+Tells curl to use the listed protocols after a redirect. See --proto for
+how protocols are represented.
+
+(Added in 7.20.2)
+.IP "--proxy-anyauth"
+Tells curl to pick a suitable authentication method when communicating with
+the given proxy. This might cause an extra request/response round-trip. (Added
+in 7.13.2)
+.IP "--proxy-basic"
+Tells curl to use HTTP Basic authentication when communicating with the given
+proxy. Use \fI--basic\fP for enabling HTTP Basic with a remote host. Basic is
+the default authentication method curl uses with proxies.
+.IP "--proxy-digest"
+Tells curl to use HTTP Digest authentication when communicating with the given
+proxy. Use \fI--digest\fP for enabling HTTP Digest with a remote host.
+.IP "--proxy-negotiate"
+Tells curl to use HTTP Negotiate authentication when communicating
+with the given proxy. Use \fI--negotiate\fP for enabling HTTP Negotiate
+with a remote host. (Added in 7.17.1)
+.IP "--proxy-ntlm"
+Tells curl to use HTTP NTLM authentication when communicating with the given
+proxy. Use \fI--ntlm\fP for enabling NTLM with a remote host.
+.IP "--proxy1.0 <proxyhost[:port]>"
+Use the specified HTTP 1.0 proxy. If the port number is not specified, it is
+assumed at port 1080.
+
+The only difference between this and the HTTP proxy option (\fI-x, --proxy\fP),
+is that attempts to use CONNECT through the proxy will specify an HTTP 1.0
+protocol instead of the default HTTP 1.1.
+.IP "--pubkey <key>"
+(SSH) Public key file name. Allows you to provide your public key in this
+separate file.
+
+If this option is used several times, the last one will be used.
+.IP "-q"
+If used as the first parameter on the command line, the \fIcurlrc\fP config
+file will not be read and used. See the \fI-K, --config\fP for details on the
+default config file search path.
+.IP "-Q, --quote <command>"
+(FTP/SFTP) Send an arbitrary command to the remote FTP or SFTP server. Quote
+commands are sent BEFORE the transfer takes place (just after the initial PWD
+command in an FTP transfer, to be exact). To make commands take place after a
+successful transfer, prefix them with a dash '-'. To make commands be sent
+after curl has changed the working directory, just before the transfer
+command(s), prefix the command with a '+' (this is only supported for
+FTP). You may specify any number of commands. If the server returns failure
+for one of the commands, the entire operation will be aborted. You must send
+syntactically correct FTP commands as RFC 959 defines to FTP servers, or one
+of the commands listed below to SFTP servers. This option can be used
+multiple times. When speaking to an FTP server, prefix the command with an
+asterisk (*) to make curl continue even if the command fails as by default
+curl will stop at first failure.
+
+SFTP is a binary protocol. Unlike for FTP, curl interprets SFTP quote commands
+itself before sending them to the server. File names may be quoted
+shell-style to embed spaces or special characters. Following is the list of
+all supported SFTP quote commands:
+.RS
+.IP "chgrp group file"
+The chgrp command sets the group ID of the file named by the file operand to
+the group ID specified by the group operand. The group operand is a decimal
+integer group ID.
+.IP "chmod mode file"
+The chmod command modifies the file mode bits of the specified file. The
+mode operand is an octal integer mode number.
+.IP "chown user file"
+The chown command sets the owner of the file named by the file operand to the
+user ID specified by the user operand. The user operand is a decimal
+integer user ID.
+.IP "ln source_file target_file"
+The ln and symlink commands create a symbolic link at the target_file location
+pointing to the source_file location.
+.IP "mkdir directory_name"
+The mkdir command creates the directory named by the directory_name operand.
+.IP "pwd"
+The pwd command returns the absolute pathname of the current working directory.
+.IP "rename source target"
+The rename command renames the file or directory named by the source
+operand to the destination path named by the target operand.
+.IP "rm file"
+The rm command removes the file specified by the file operand.
+.IP "rmdir directory"
+The rmdir command removes the directory entry specified by the directory
+operand, provided it is empty.
+.IP "symlink source_file target_file"
+See ln.
+.RE
+.IP "-r, --range <range>"
+(HTTP/FTP/SFTP/FILE) Retrieve a byte range (i.e a partial document) from a
+HTTP/1.1, FTP or SFTP server or a local FILE. Ranges can be specified
+in a number of ways.
+.RS
+.TP 10
+.B 0-499
+specifies the first 500 bytes
+.TP
+.B 500-999
+specifies the second 500 bytes
+.TP
+.B -500
+specifies the last 500 bytes
+.TP
+.B 9500-
+specifies the bytes from offset 9500 and forward
+.TP
+.B 0-0,-1
+specifies the first and last byte only(*)(H)
+.TP
+.B 500-700,600-799
+specifies 300 bytes from offset 500(H)
+.TP
+.B 100-199,500-599
+specifies two separate 100-byte ranges(*)(H)
+.RE
+
+(*) = NOTE that this will cause the server to reply with a multipart
+response!
+
+Only digit characters (0-9) are valid in the 'start' and 'stop' fields of the
+\&'start-stop' range syntax. If a non-digit character is given in the range,
+the server's response will be unspecified, depending on the server's
+configuration.
+
+You should also be aware that many HTTP/1.1 servers do not have this feature
+enabled, so that when you attempt to get a range, you'll instead get the whole
+document.
+
+FTP and SFTP range downloads only support the simple 'start-stop' syntax
+(optionally with one of the numbers omitted). FTP use depends on the extended
+FTP command SIZE.
+
+If this option is used several times, the last one will be used.
+.IP "-R, --remote-time"
+When used, this will make curl attempt to figure out the timestamp of the
+remote file, and if that is available make the local file get that same
+timestamp.
+.IP "--random-file <file>"
+(SSL) Specify the path name to file containing what will be considered as
+random data. The data is used to seed the random engine for SSL connections.
+See also the \fI--egd-file\fP option.
+.IP "--raw"
+(HTTP) When used, it disables all internal HTTP decoding of content or transfer
+encodings and instead makes them passed on unaltered, raw. (Added in 7.16.2)
+.IP "--remote-name-all"
+This option changes the default action for all given URLs to be dealt with as
+if \fI-O, --remote-name\fP were used for each one. So if you want to disable
+that for a specific URL after \fI--remote-name-all\fP has been used, you must
+use "-o -" or \fI--no-remote-name\fP. (Added in 7.19.0)
+.IP "--resolve <host:port:address>"
+Provide a custom address for a specific host and port pair. Using this, you
+can make the curl requests(s) use a specified address and prevent the
+otherwise normally resolved address to be used. Consider it a sort of
+/etc/hosts alternative provided on the command line. The port number should be
+the number used for the specific protocol the host will be used for. It means
+you need several entries if you want to provide address for the same host but
+different ports.
+
+This option can be used many times to add many host names to resolve.
+
+(Added in 7.21.3)
+.IP "--retry <num>"
+If a transient error is returned when curl tries to perform a transfer, it
+will retry this number of times before giving up. Setting the number to 0
+makes curl do no retries (which is the default). Transient error means either:
+a timeout, an FTP 4xx response code or an HTTP 5xx response code.
+
+When curl is about to retry a transfer, it will first wait one second and then
+for all forthcoming retries it will double the waiting time until it reaches
+10 minutes which then will be the delay between the rest of the retries. By
+using \fI--retry-delay\fP you disable this exponential backoff algorithm. See
+also \fI--retry-max-time\fP to limit the total time allowed for
+retries. (Added in 7.12.3)
+
+If this option is used several times, the last one will be used.
+.IP "--retry-delay <seconds>"
+Make curl sleep this amount of time before each retry when a transfer has
+failed with a transient error (it changes the default backoff time algorithm
+between retries). This option is only interesting if \fI--retry\fP is also
+used. Setting this delay to zero will make curl use the default backoff time.
+(Added in 7.12.3)
+
+If this option is used several times, the last one will be used.
+.IP "--retry-max-time <seconds>"
+The retry timer is reset before the first transfer attempt. Retries will be
+done as usual (see \fI--retry\fP) as long as the timer hasn't reached this
+given limit. Notice that if the timer hasn't reached the limit, the request
+will be made and while performing, it may take longer than this given time
+period. To limit a single request\'s maximum time, use \fI-m, --max-time\fP.
+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. 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"
+(FTP, POP3, IMAP, SMTP) Try to use SSL/TLS for the connection. Reverts to a
+non-secure connection if the server doesn't support SSL/TLS. See also
+\fI--ftp-ssl-control\fP and \fI--ssl-reqd\fP for different levels of
+encryption required. (Added in 7.20.0)
+
+This option was formerly known as \fI--ftp-ssl\fP (Added in 7.11.0). That
+option name can still be used but will be removed in a future version.
+.IP "--ssl-reqd"
+(FTP, POP3, IMAP, SMTP) Require SSL/TLS for the connection. Terminates the
+connection if the server doesn't support SSL/TLS. (Added in 7.20.0)
+
+This option was formerly known as \fI--ftp-ssl-reqd\fP (added in 7.15.5). That
+option name can still be used but will be removed in a future version.
+.IP "--ssl-allow-beast"
+(SSL) This option tells curl to not work around a security flaw in the SSL3
+and TLS1.0 protocols known as BEAST. If this option isn't used, the SSL layer
+may use work-arounds known to cause interoperability problems with some older
+SSL implementations. WARNING: this option loosens the SSL security, and by
+using this flag you ask for exactly that. (Added in 7.25.0)
+.IP "--socks4 <host[:port]>"
+Use the specified SOCKS4 proxy. If the port number is not specified, it is
+assumed at port 1080. (Added in 7.15.2)
+
+This option overrides any previous use of \fI-x, --proxy\fP, as they are
+mutually exclusive.
+
+Since 7.21.7, this option is superfluous since you can specify a socks4 proxy
+with \fI-x, --proxy\fP using a socks4:// protocol prefix.
+
+If this option is used several times, the last one will be used.
+.IP "--socks4a <host[:port]>"
+Use the specified SOCKS4a proxy. If the port number is not specified, it is
+assumed at port 1080. (Added in 7.18.0)
+
+This option overrides any previous use of \fI-x, --proxy\fP, as they are
+mutually exclusive.
+
+Since 7.21.7, this option is superfluous since you can specify a socks4a proxy
+with \fI-x, --proxy\fP using a socks4a:// protocol prefix.
+
+If this option is used several times, the last one will be used.
+.IP "--socks5-hostname <host[:port]>"
+Use the specified SOCKS5 proxy (and let the proxy resolve the host name). If
+the port number is not specified, it is assumed at port 1080. (Added in
+7.18.0)
+
+This option overrides any previous use of \fI-x, --proxy\fP, as they are
+mutually exclusive.
+
+Since 7.21.7, this option is superfluous since you can specify a socks5
+hostname proxy with \fI-x, --proxy\fP using a socks5h:// protocol prefix.
+
+If this option is used several times, the last one will be used. (This option
+was previously wrongly documented and used as --socks without the number
+appended.)
+.IP "--socks5 <host[:port]>"
+Use the specified SOCKS5 proxy - but resolve the host name locally. If the
+port number is not specified, it is assumed at port 1080.
+
+This option overrides any previous use of \fI-x, --proxy\fP, as they are
+mutually exclusive.
+
+Since 7.21.7, this option is superfluous since you can specify a socks5 proxy
+with \fI-x, --proxy\fP using a socks5:// protocol prefix.
+
+If this option is used several times, the last one will be used. (This option
+was previously wrongly documented and used as --socks without the number
+appended.)
+
+This option (as well as \fI--socks4\fP) does not work with IPV6, FTPS or LDAP.
+.IP "--socks5-gssapi-service <servicename>"
+The default service name for a socks server is rcmd/server-fqdn. This option
+allows you to change it.
+
+Examples: --socks5 proxy-name \fI--socks5-gssapi-service\fP sockd would use
+sockd/proxy-name --socks5 proxy-name \fI--socks5-gssapi-service\fP
+sockd/real-name would use sockd/real-name for cases where the proxy-name does
+not match the principal name. (Added in 7.19.4).
+.IP "--socks5-gssapi-nec"
+As part of the gssapi negotiation a protection mode is negotiated. RFC 1961
+says in section 4.3/4.4 it should be protected, but the NEC reference
+implementation does not. The option \fI--socks5-gssapi-nec\fP allows the
+unprotected exchange of the protection mode negotiation. (Added in 7.19.4).
+.IP "--stderr <file>"
+Redirect all writes to stderr to the specified file instead. If the file name
+is a plain '-', it is instead written to stdout.
+
+If this option is used several times, the last one will be used.
+.IP "-t, --telnet-option <OPT=val>"
+Pass options to the telnet protocol. Supported options are:
+
+TTYPE=<term> Sets the terminal type.
+
+XDISPLOC=<X display> Sets the X display location.
+
+NEW_ENV=<var,val> Sets an environment variable.
+.IP "-T, --upload-file <file>"
+This transfers the specified local file to the remote URL. If there is no file
+part in the specified URL, Curl will append the local file name. NOTE that you
+must use a trailing / on the last directory to really prove to Curl that there
+is no file name or curl will think that your last directory name is the remote
+file name to use. That will most likely cause the upload operation to fail. If
+this is used on an HTTP(S) server, the PUT command will be used.
+
+Use the file name "-" (a single dash) to use stdin instead of a given file.
+Alternately, the file name "." (a single period) may be specified instead
+of "-" to use stdin in non-blocking mode to allow reading server output
+while stdin is being uploaded.
+
+You can specify one -T for each URL on the command line. Each -T + URL pair
+specifies what to upload and to where. curl also supports "globbing" of the -T
+argument, meaning that you can upload multiple files to a single URL by using
+the same URL globbing style supported in the URL, like this:
+
+curl -T "{file1,file2}" http://www.uploadtothissite.com
+
+or even
+
+curl -T "img[1-1000].png" ftp://ftp.picturemania.com/upload/
+.IP "--tcp-nodelay"
+Turn on the TCP_NODELAY option. See the \fIcurl_easy_setopt(3)\fP man page for
+details about this option. (Added in 7.11.2)
+.IP "--tftp-blksize <value>"
+(TFTP) Set TFTP BLKSIZE option (must be >512). This is the block size that
+curl will try to use when transferring data to or from a TFTP server. By
+default 512 bytes will be used.
+
+If this option is used several times, the last one will be used.
+
+(Added in 7.20.0)
+.IP "--tlsauthtype <authtype>"
+Set TLS authentication type. Currently, the only supported option is "SRP",
+for TLS-SRP (RFC 5054). If \fI--tlsuser\fP and \fI--tlspassword\fP are
+specified but \fI--tlsauthtype\fP is not, then this option defaults to "SRP".
+(Added in 7.21.4)
+.IP "--tlsuser <user>"
+Set username for use with the TLS authentication method specified with
+\fI--tlsauthtype\fP. Requires that \fI--tlspassword\fP also be set. (Added in
+7.21.4)
+.IP "--tlspassword <password>"
+Set password for use with the TLS authentication method specified with
+\fI--tlsauthtype\fP. Requires that \fI--tlsuser\fP also be set. (Added in
+7.21.4)
+.IP "--tr-encoding"
+(HTTP) Request a compressed Transfer-Encoding response using one of the
+algorithms curl supports, and uncompress the data while receiving it.
+
+(Added in 7.21.6)
+.IP "--trace <file>"
+Enables a full trace dump of all incoming and outgoing data, including
+descriptive information, to the given output file. Use "-" as filename to have
+the output sent to stdout.
+
+This option overrides previous uses of \fI-v, --verbose\fP or
+\fI--trace-ascii\fP.
+
+If this option is used several times, the last one will be used.
+.IP "--trace-ascii <file>"
+Enables a full trace dump of all incoming and outgoing data, including
+descriptive information, to the given output file. Use "-" as filename to have
+the output sent to stdout.
+
+This is very similar to \fI--trace\fP, but leaves out the hex part and only
+shows the ASCII part of the dump. It makes smaller output that might be easier
+to read for untrained humans.
+
+This option overrides previous uses of \fI-v, --verbose\fP or \fI--trace\fP.
+
+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;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 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 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>"
+Specify the user name and password to use for proxy authentication.
+
+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 this option is used several times, the last one will be used.
+.IP "--url <URL>"
+Specify a URL to fetch. This option is mostly handy when you want to specify
+URL(s) in a config file.
+
+This option may be used any number of times. To control where this URL is
+written, use the \fI-o, --output\fP or the \fI-O, --remote-name\fP options.
+.IP "-v, --verbose"
+Makes the fetching more verbose/talkative. Mostly useful for debugging. A line
+starting with '>' means "header data" sent by curl, '<' means "header data"
+received by curl that is hidden in normal cases, and a line starting with '*'
+means additional info provided by curl.
+
+Note that if you only want HTTP headers in the output, \fI-i, --include\fP
+might be the option you're looking for.
+
+If you think this option still doesn't give you enough details, consider using
+\fI--trace\fP or \fI--trace-ascii\fP instead.
+
+This option overrides previous uses of \fI--trace-ascii\fP or \fI--trace\fP.
+
+Use \fI-s, --silent\fP to make curl quiet.
+.IP "-w, --write-out <format>"
+Defines what to display on stdout after a completed and successful
+operation. The format is a string that may contain plain text mixed with any
+number of variables. The string can be specified as "string", to get read from
+a particular file you specify it "@filename" and to tell curl to read the
+format from stdin you write "@-".
+
+The variables present in the output format will be substituted by the value or
+text that curl thinks fit, as described below. All variables are specified
+as %{variable_name} and to output a normal % you just write them as
+%%. You can output a newline by using \\n, a carriage return with \\r and a tab
+space with \\t.
+
+.B NOTE:
+The %-symbol is a special symbol in the win32-environment, where all
+occurrences of % must be doubled when using this option.
+
+The variables available are:
+.RS
+.TP 15
+.B content_type
+The Content-Type of the requested document, if there was any.
+.TP
+.B filename_effective
+The ultimate filename that curl writes out to. This is only meaningful if curl
+is told to write to a file with the \fI--remote-name\fP or \fI--output\fP
+option. It's most useful in combination with the \fI--remote-header-name\fP
+option. (Added in 7.25.1)
+.TP
+.B ftp_entry_path
+The initial path curl ended up in when logging on to the remote FTP
+server. (Added in 7.15.4)
+.TP
+.B http_code
+The numerical response code that was found in the last retrieved HTTP(S) or
+FTP(s) transfer. In 7.18.2 the alias \fBresponse_code\fP was added to show the
+same info.
+.TP
+.B http_connect
+The numerical code that was found in the last response (from a proxy) to a
+curl CONNECT request. (Added in 7.12.4)
+.TP
+.B local_ip
+The IP address of the local end of the most recently done connection - can be
+either IPv4 or IPv6 (Added in 7.29.0)
+.TP
+.B local_port
+The local port number of the most recently done connection (Added in 7.29.0)
+.TP
+.B num_connects
+Number of new connects made in the recent transfer. (Added in 7.12.3)
+.TP
+.B num_redirects
+Number of redirects that were followed in the request. (Added in 7.12.3)
+.TP
+.B redirect_url
+When an HTTP request was made without -L to follow redirects, this variable
+will show the actual URL a redirect \fIwould\fP take you to. (Added in 7.18.2)
+.TP
+.B remote_ip
+The remote IP address of the most recently done connection - can be either
+IPv4 or IPv6 (Added in 7.29.0)
+.TP
+.B remote_port
+The remote port number of the most recently done connection (Added in 7.29.0)
+.TP
+.B size_download
+The total amount of bytes that were downloaded.
+.TP
+.B size_header
+The total amount of bytes of the downloaded headers.
+.TP
+.B size_request
+The total amount of bytes that were sent in the HTTP request.
+.TP
+.B size_upload
+The total amount of bytes that were uploaded.
+.TP
+.B speed_download
+The average download speed that curl measured for the complete download. Bytes
+per second.
+.TP
+.B speed_upload
+The average upload speed that curl measured for the complete upload. Bytes per
+second.
+.TP
+.B ssl_verify_result
+The result of the SSL peer certificate verification that was requested. 0
+means the verification was successful. (Added in 7.19.0)
+.TP
+.B time_appconnect
+The time, in seconds, it took from the start until the SSL/SSH/etc
+connect/handshake to the remote host was completed. (Added in 7.19.0)
+.TP
+.B time_connect
+The time, in seconds, it took from the start until the TCP connect to the
+remote host (or proxy) was completed.
+.TP
+.B time_namelookup
+The time, in seconds, it took from the start until the name resolving was
+completed.
+.TP
+.B time_pretransfer
+The time, in seconds, it took from the start until the file transfer was just
+about to begin. This includes all pre-transfer commands and negotiations that
+are specific to the particular protocol(s) involved.
+.TP
+.B time_redirect
+The time, in seconds, it took for all redirection steps include name lookup,
+connect, pretransfer and transfer before the final transaction was
+started. time_redirect shows the complete execution time for multiple
+redirections. (Added in 7.12.3)
+.TP
+.B time_starttransfer
+The time, in seconds, it took from the start until the first byte was just
+about to be transferred. This includes time_pretransfer and also the time the
+server needed to calculate the result.
+.TP
+.B time_total
+The total time, in seconds, that the full operation lasted. The time will be
+displayed with millisecond resolution.
+.TP
+.B url_effective
+The URL that was fetched last. This is most meaningful if you've told curl
+to follow location: headers.
+.RE
+
+If this option is used several times, the last one will be used.
+.IP "-x, --proxy <[protocol://][user:password@]proxyhost[:port]>"
+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
+\&"" to override it.
+
+All operations that are performed over an HTTP proxy will transparently be
+converted to HTTP. It means that certain protocol specific operations might
+not be available. This is not the case if you can tunnel through the proxy, as
+one with the \fI-p, --proxytunnel\fP option.
+
+User and password that might be provided in the proxy string are URL decoded
+by curl. This allows you to pass in special characters such as @ by using %40
+or pass in a colon with %3a.
+
+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.
+
+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
+HTTP server. The specified request will be used instead of the method
+otherwise used (which defaults to GET). Read the HTTP 1.1 specification for
+details and explanations. Common additional HTTP requests include PUT and
+DELETE, but related technologies like WebDAV offers PROPFIND, COPY, MOVE and
+more.
+
+Normally you don't need this option. All sorts of GET, HEAD, POST and PUT
+requests are rather invoked by using dedicated command line options.
+
+This option only changes the actual word used in the HTTP request, it does not
+alter the way curl behaves. So for example if you want to make a proper HEAD
+request, using -X HEAD will not suffice. You need to use the \fI-I, --head\fP
+option.
+
+(FTP)
+Specifies a custom FTP command to use instead of LIST when doing file lists
+with FTP.
+
+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 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.
+
+.IP "-y, --speed-time <time>"
+If a download is slower than speed-limit bytes per second during a speed-time
+period, the download gets aborted. If speed-time is used, the default
+speed-limit will be 1 unless set with \fI-Y\fP.
+
+This option controls transfers and thus will not affect slow connects etc. If
+this is a concern for you, try the \fI--connect-timeout\fP option.
+
+If this option is used several times, the last one will be used.
+.IP "-Y, --speed-limit <speed>"
+If a download is slower than this given speed (in bytes per second) for
+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>"
+(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
+is taken as a filename and tries to get the modification date (mtime) from
+<file> instead. See the \fIcurl_getdate(3)\fP man pages for date expression
+details.
+
+Start the date expression with a dash (-) to make it request for a document
+that is older than the given date/time, default is a document that is newer
+than the specified date/time.
+
+If this option is used several times, the last one will be used.
+.IP "-h, --help"
+Usage help.
+.IP "-M, --manual"
+Manual. Display the huge help text.
+.IP "-V, --version"
+Displays information about curl and the libcurl version it uses.
+
+The first line includes the full version of curl, libcurl and other 3rd party
+libraries linked with the executable.
+
+The second line (starts with "Protocols:") shows all protocols that libcurl
+reports to support.
+
+The third line (starts with "Features:") shows specific features libcurl
+reports to offer. Available features include:
+.RS
+.IP "IPv6"
+You can use IPv6 with this.
+.IP "krb4"
+Krb4 for FTP is supported.
+.IP "SSL"
+HTTPS and FTPS are supported.
+.IP "libz"
+Automatic decompression of compressed files over HTTP is supported.
+.IP "NTLM"
+NTLM authentication is supported.
+.IP "GSS-Negotiate"
+Negotiate authentication and krb5 for FTP is supported.
+.IP "Debug"
+This curl uses a libcurl built with Debug. This enables more error-tracking
+and memory debugging etc. For curl-developers only!
+.IP "AsynchDNS"
+This curl uses asynchronous name resolves.
+.IP "SPNEGO"
+SPNEGO Negotiate authentication is supported.
+.IP "Largefile"
+This curl supports transfers of large files, files larger than 2GB.
+.IP "IDN"
+This curl supports IDN - international domain names.
+.IP "SSPI"
+SSPI is supported. If you use NTLM and set a blank user name, curl will
+authenticate with your current user and password.
+.IP "TLS-SRP"
+SRP (Secure Remote Password) authentication is supported for TLS.
+.IP "Metalink"
+This curl supports Metalink (both version 3 and 4 (RFC 5854)), which
+describes mirrors and hashes. curl will use mirrors for failover if
+there are errors (such as the file or server not being available).
+.RE
+.SH FILES
+.I ~/.curlrc
+.RS
+Default config file, see \fI-K, --config\fP for details.
+.SH ENVIRONMENT
+The environment variables can be specified in lower case or upper case. The
+lower case version has precedence. http_proxy is an exception as it is only
+available in lower case.
+
+Using an environment variable to set the proxy has the same effect as using
+the \fI--proxy\fP option.
+
+.IP "http_proxy [protocol://]<host>[:port]"
+Sets the proxy server to use for HTTP.
+.IP "HTTPS_PROXY [protocol://]<host>[:port]"
+Sets the proxy server to use for HTTPS.
+.IP "[url-protocol]_PROXY [protocol://]<host>[:port]"
+Sets the proxy server to use for [url-protocol], where the protocol is a
+protocol that curl supports and as specified in a URL. FTP, FTPS, POP3, IMAP,
+SMTP, LDAP etc.
+.IP "ALL_PROXY [protocol://]<host>[:port]"
+Sets the proxy server to use if no protocol-specific proxy is set.
+.IP "NO_PROXY <comma-separated list of hosts>"
+list of host names that shouldn't go through any proxy. If set to a asterisk
+\&'*' only, it matches all hosts.
+.SH "PROXY PROTOCOL PREFIXES"
+Since curl version 7.21.7, the proxy string may be specified with a
+protocol:// prefix to specify alternative proxy protocols.
+
+If no protocol is specified in the proxy string or if the string doesn't match
+a supported one, the proxy will be treated as an HTTP proxy.
+
+The supported proxy protocol prefixes are as follows:
+.IP "socks4://"
+Makes it the equivalent of \fI--socks4\fP
+.IP "socks4a://"
+Makes it the equivalent of \fI--socks4a\fP
+.IP "socks5://"
+Makes it the equivalent of \fI--socks5\fP
+.IP "socks5h://"
+Makes it the equivalent of \fI--socks5-hostname\fP
+.SH EXIT CODES
+There are a bunch of different error codes and their corresponding error
+messages that may appear during bad conditions. At the time of this writing,
+the exit codes are:
+.IP 1
+Unsupported protocol. This build of curl has no support for this protocol.
+.IP 2
+Failed to initialize.
+.IP 3
+URL malformed. The syntax was not correct.
+.IP 4
+A feature or option that was needed to perform the desired request was not
+enabled or was explicitly disabled at build-time. To make curl able to do
+this, you probably need another build of libcurl!
+.IP 5
+Couldn't resolve proxy. The given proxy host could not be resolved.
+.IP 6
+Couldn't resolve host. The given remote host was not resolved.
+.IP 7
+Failed to connect to host.
+.IP 8
+FTP weird server reply. The server sent data curl couldn't parse.
+.IP 9
+FTP access denied. The server denied login or denied access to the particular
+resource or directory you wanted to reach. Most often you tried to change to a
+directory that doesn't exist on the server.
+.IP 11
+FTP weird PASS reply. Curl couldn't parse the reply sent to the PASS request.
+.IP 13
+FTP weird PASV reply, Curl couldn't parse the reply sent to the PASV request.
+.IP 14
+FTP weird 227 format. Curl couldn't parse the 227-line the server sent.
+.IP 15
+FTP can't get host. Couldn't resolve the host IP we got in the 227-line.
+.IP 17
+FTP couldn't set binary. Couldn't change transfer method to binary.
+.IP 18
+Partial file. Only a part of the file was transferred.
+.IP 19
+FTP couldn't download/access the given file, the RETR (or similar) command
+failed.
+.IP 21
+FTP quote error. A quote command returned error from the server.
+.IP 22
+HTTP page not retrieved. The requested url was not found or returned another
+error with the HTTP error code being 400 or above. This return code only
+appears if \fI-f, --fail\fP is used.
+.IP 23
+Write error. Curl couldn't write data to a local filesystem or similar.
+.IP 25
+FTP couldn't STOR file. The server denied the STOR operation, used for FTP
+uploading.
+.IP 26
+Read error. Various reading problems.
+.IP 27
+Out of memory. A memory allocation request failed.
+.IP 28
+Operation timeout. The specified time-out period was reached according to the
+conditions.
+.IP 30
+FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT
+command, try doing a transfer using PASV instead!
+.IP 31
+FTP couldn't use REST. The REST command failed. This command is used for
+resumed FTP transfers.
+.IP 33
+HTTP range error. The range "command" didn't work.
+.IP 34
+HTTP post error. Internal post-request generation error.
+.IP 35
+SSL connect error. The SSL handshaking failed.
+.IP 36
+FTP bad download resume. Couldn't continue an earlier aborted download.
+.IP 37
+FILE couldn't read file. Failed to open the file. Permissions?
+.IP 38
+LDAP cannot bind. LDAP bind operation failed.
+.IP 39
+LDAP search failed.
+.IP 41
+Function not found. A required LDAP function was not found.
+.IP 42
+Aborted by callback. An application told curl to abort the operation.
+.IP 43
+Internal error. A function was called with a bad parameter.
+.IP 45
+Interface error. A specified outgoing interface could not be used.
+.IP 47
+Too many redirects. When following redirects, curl hit the maximum amount.
+.IP 48
+Unknown option specified to libcurl. This indicates that you passed a weird
+option to curl that was passed on to libcurl and rejected. Read up in the
+manual!
+.IP 49
+Malformed telnet option.
+.IP 51
+The peer's SSL certificate or SSH MD5 fingerprint was not OK.
+.IP 52
+The server didn't reply anything, which here is considered an error.
+.IP 53
+SSL crypto engine not found.
+.IP 54
+Cannot set SSL crypto engine as default.
+.IP 55
+Failed sending network data.
+.IP 56
+Failure in receiving network data.
+.IP 58
+Problem with the local certificate.
+.IP 59
+Couldn't use specified SSL cipher.
+.IP 60
+Peer certificate cannot be authenticated with known CA certificates.
+.IP 61
+Unrecognized transfer encoding.
+.IP 62
+Invalid LDAP URL.
+.IP 63
+Maximum file size exceeded.
+.IP 64
+Requested FTP SSL level failed.
+.IP 65
+Sending the data requires a rewind that failed.
+.IP 66
+Failed to initialise SSL Engine.
+.IP 67
+The user name, password, or similar was not accepted and curl failed to log in.
+.IP 68
+File not found on TFTP server.
+.IP 69
+Permission problem on TFTP server.
+.IP 70
+Out of disk space on TFTP server.
+.IP 71
+Illegal TFTP operation.
+.IP 72
+Unknown TFTP transfer ID.
+.IP 73
+File already exists (TFTP).
+.IP 74
+No such user (TFTP).
+.IP 75
+Character conversion failed.
+.IP 76
+Character conversion functions required.
+.IP 77
+Problem with reading the SSL CA cert (path? access rights?).
+.IP 78
+The resource referenced in the URL does not exist.
+.IP 79
+An unspecified error occurred during the SSH session.
+.IP 80
+Failed to shut down the SSL connection.
+.IP 82
+Could not load CRL file, missing or wrong format (added in 7.19.0).
+.IP 83
+Issuer check failed (added in 7.19.0).
+.IP 84
+The FTP PRET command failed
+.IP 85
+RTSP: mismatch of CSeq numbers
+.IP 86
+RTSP: mismatch of Session Identifiers
+.IP 87
+unable to parse FTP file list
+.IP 88
+FTP chunk callback reported error
+.IP XX
+More error codes will appear here in future releases. The existing ones
+are meant to never change.
+.SH AUTHORS / CONTRIBUTORS
+Daniel Stenberg is the main author, but the whole list of contributors is
+found in the separate THANKS file.
+.SH WWW
+http://curl.haxx.se
+.SH FTP
+ftp://ftp.sunet.se/pub/www/utilities/curl/
+.SH "SEE ALSO"
+.BR ftp (1),
+.BR wget (1)
diff --git a/libs/libcurl/docs/curl.html b/libs/libcurl/docs/curl.html
new file mode 100644
index 0000000000..c04a69633d
--- /dev/null
+++ b/libs/libcurl/docs/curl.html
@@ -0,0 +1,961 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<title>curl man page</title>
+<meta name="generator" content="roffit">
+<STYLE type="text/css">
+P.level0 {
+ padding-left: 2em;
+}
+
+P.level1 {
+ padding-left: 4em;
+}
+
+P.level2 {
+ padding-left: 6em;
+}
+
+span.emphasis {
+ font-style: italic;
+}
+
+span.bold {
+ font-weight: bold;
+}
+
+span.manpage {
+ font-weight: bold;
+}
+
+h2.nroffsh {
+ background-color: #e0e0e0;
+}
+
+span.nroffip {
+ font-weight: bold;
+ font-size: 120%;
+ font-family: monospace;
+}
+
+p.roffit {
+ text-align: center;
+ font-size: 80%;
+}
+</STYLE>
+</head><body>
+
+<p class="level0"><a name="NAME"></a><h2 class="nroffsh">NAME</h2>
+<p class="level0">curl - transfer a URL <a name="SYNOPSIS"></a><h2 class="nroffsh">SYNOPSIS</h2>
+<p class="level0"><span Class="bold">curl [options]</span> <a class="emphasis" href="#URL">[URL...]</a> <a name="DESCRIPTION"></a><h2 class="nroffsh">DESCRIPTION</h2>
+<p class="level0"><span Class="bold">curl</span> is a tool to transfer data from or to a server, using one of the supported protocols (DICT, FILE, FTP, FTPS, GOPHER, HTTP, HTTPS, IMAP, IMAPS, LDAP, LDAPS, POP3, POP3S, RTMP, RTSP, SCP, SFTP, SMTP, SMTPS, TELNET and TFTP). The command is designed to work without user interaction.
+<p class="level0">curl offers a busload of useful tricks like proxy support, user authentication, FTP upload, HTTP post, SSL connections, cookies, file transfer resume, Metalink, and more. As you will see below, the number of features will make your head spin!
+<p class="level0">curl is powered by libcurl for all transfer-related features. See <span Class="manpage">libcurl (3)</span> for details. <a name="URL"></a><h2 class="nroffsh">URL</h2>
+<p class="level0">The URL syntax is protocol-dependent. You'll find a detailed description in <a href="http://www.ietf.org/rfc/rfc3986.txt">RFC 3986</a>.
+<p class="level0">You can specify multiple URLs or parts of URLs by writing part sets within braces as in:
+<p class="level0">&nbsp;<a href="http://site">http://site</a>.{one,two,three}.com
+<p class="level0">or you can get sequences of alphanumeric series by using [] as in:
+<p class="level0">&nbsp;<a href="ftp://ftp.numericals.com/file">ftp://ftp.numericals.com/file</a>[1-100].txt &nbsp;<a href="ftp://ftp.numericals.com/file">ftp://ftp.numericals.com/file</a>[001-100].txt (with leading zeros) &nbsp;<a href="ftp://ftp.letters.com/file">ftp://ftp.letters.com/file</a>[a-z].txt
+<p class="level0">Nested sequences are not supported, but you can use several ones next to each other:
+<p class="level0">&nbsp;<a href="http://any.org/archive">http://any.org/archive</a>[1996-1999]/vol[1-4]/part{a,b,c}.html
+<p class="level0">You can specify any amount of URLs on the command line. They will be fetched in a sequential manner in the specified order.
+<p class="level0">You can specify a step counter for the ranges to get every Nth number or letter:
+<p class="level0">&nbsp;<a href="http://www.numericals.com/file">http://www.numericals.com/file</a>[1-100:10].txt &nbsp;<a href="http://www.letters.com/file">http://www.letters.com/file</a>[a-z:2].txt
+<p class="level0">If you specify URL without protocol:// prefix, curl will attempt to guess what protocol you might want. It will then default to HTTP but try other protocols based on often-used host name prefixes. For example, for host names starting with "ftp." curl will assume you want to speak FTP.
+<p class="level0">curl will do its best to use what you pass to it as a URL. It is not trying to validate it as a syntactically correct URL by any means but is instead <span Class="bold">very</span> liberal with what it accepts.
+<p class="level0">curl will attempt to re-use connections for multiple file transfers, so that getting many files from the same server will not do multiple connects / handshakes. This improves speed. Of course this is only done on files specified on a single command line and cannot be used between separate curl invokes. <a name="PROGRESS"></a><h2 class="nroffsh">PROGRESS METER</h2>
+<p class="level0">curl normally displays a progress meter during operations, indicating the amount of transferred data, transfer speeds and estimated time left, etc.
+<p class="level0">curl displays this data to the terminal by default, so if you invoke curl to do an operation and it is about to write data to the terminal, it <span Class="emphasis">disables</span> the progress meter as otherwise it would mess up the output mixing progress meter and response data.
+<p class="level0">If you want a progress meter for HTTP POST or PUT requests, you need to redirect the response output to a file, using shell redirect (&gt;), -o [file] or similar.
+<p class="level0">It is not the same case for FTP upload as that operation does not spit out any response data to the terminal.
+<p class="level0">If you prefer a progress "bar" instead of the regular meter, <a class="emphasis" href="#-">-#</a> is your friend. <a name="OPTIONS"></a><h2 class="nroffsh">OPTIONS</h2>
+<p class="level0">Options start with one or two dashes. Many of the options require an addition value next to it.
+<p class="level0">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.
+<p class="level0">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.
+<p class="level0">In general, all boolean options are enabled with --<span Class="bold">option</span> and yet again disabled with --<span Class="bold">no-</span>option. That is, you use the exact same option name but prefix it with "no-". However, in this list we mostly only list and show the --option version of them. (This concept with --no options was added in 7.19.0. Previously most options were toggled on/off on repeated use of the same command line option.)
+<p class="level0"><a name="-"></a><span class="nroffip">-#, --progress-bar</span>
+<p class="level1">Make curl display progress as a simple progress bar instead of the standard, more informational, meter.
+<p class="level0"><a name="-0"></a><span class="nroffip">-0, --http1.0</span>
+<p class="level1">(HTTP) Tells curl to use HTTP version 1.0 instead of using its internally preferred: HTTP 1.1.
+<p class="level0"><a name="--http11"></a><span class="nroffip">--http1.1</span>
+<p class="level1">(HTTP) Tells curl to use HTTP version 1.1. This is the internal default version. (Added in 7.33.0)
+<p class="level0"><a name="--http20"></a><span class="nroffip">--http2.0</span>
+<p class="level1">(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)
+<p class="level0"><a name="-1"></a><span class="nroffip">-1, --tlsv1</span>
+<p class="level1">(SSL) Forces curl to use TLS version 1 when negotiating with a remote TLS server.
+<p class="level0"><a name="-2"></a><span class="nroffip">-2, --sslv2</span>
+<p class="level1">(SSL) Forces curl to use SSL version 2 when negotiating with a remote SSL server.
+<p class="level0"><a name="-3"></a><span class="nroffip">-3, --sslv3</span>
+<p class="level1">(SSL) Forces curl to use SSL version 3 when negotiating with a remote SSL server.
+<p class="level0"><a name="-4"></a><span class="nroffip">-4, --ipv4</span>
+<p class="level1">If curl is capable of resolving an address to multiple IP versions (which it is if it is IPv6-capable), this option tells curl to resolve names to IPv4 addresses only.
+<p class="level0"><a name="-6"></a><span class="nroffip">-6, --ipv6</span>
+<p class="level1">If curl is capable of resolving an address to multiple IP versions (which it is if it is IPv6-capable), this option tells curl to resolve names to IPv6 addresses only.
+<p class="level0"><a name="-a"></a><span class="nroffip">-a, --append</span>
+<p class="level1">(FTP/SFTP) When used in an upload, this will tell curl to append to the target file instead of overwriting it. If the file doesn't exist, it will be created. Note that this flag is ignored by some SSH servers (including OpenSSH).
+<p class="level0"><a name="-A"></a><span class="nroffip">-A, --user-agent &lt;agent string&gt;</span>
+<p class="level1">(HTTP) Specify the User-Agent string to send to the HTTP server. Some badly done CGIs fail if this field isn't set to "Mozilla/4.0". To encode blanks in the string, surround the string with single quote marks. This can also be set with the <a class="emphasis" href="#-H">-H, --header</a> option of course.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--anyauth"></a><span class="nroffip">--anyauth</span>
+<p class="level1">(HTTP) Tells curl to figure out authentication method by itself, and use the most secure one the remote site claims to support. This is done by first doing a request and checking the response-headers, thus possibly inducing an extra network round-trip. This is used instead of setting a specific authentication method, which you can do with <a class="emphasis" href="#--basic">--basic</a>, <a class="emphasis" href="#--digest">--digest</a>, <a class="emphasis" href="#--ntlm">--ntlm</a>, and <a class="emphasis" href="#--negotiate">--negotiate</a>.
+<p class="level1">Note that using --anyauth is not recommended if you do uploads from stdin, since it may require data to be sent twice and then the client must be able to rewind. If the need should arise when uploading from stdin, the upload operation will fail.
+<p class="level0"><a name="-b"></a><span class="nroffip">-b, --cookie &lt;name=data&gt;</span>
+<p class="level1">(HTTP) Pass the data to the HTTP server as a cookie. It is supposedly the data previously received from the server in a "Set-Cookie:" line. The data should be in the format "NAME1=VALUE1; NAME2=VALUE2".
+<p class="level1">If no '=' symbol is used in the line, it is treated as a filename to use to read previously stored cookie lines from, which should be used in this session if they match. Using this method also activates the "cookie parser" which will make curl record incoming cookies too, which may be handy if you're using this in combination with the <a class="emphasis" href="#-L">-L, --location</a> option. The file format of the file to read cookies from should be plain HTTP headers or the Netscape/Mozilla cookie file format.
+<p class="level1"><span Class="bold">NOTE</span> that the file specified with <a class="emphasis" href="#-b">-b, --cookie</a> is only used as input. No cookies will be stored in the file. To store cookies, use the <a class="emphasis" href="#-c">-c, --cookie-jar</a> option or you could even save the HTTP headers to a file using <a class="emphasis" href="#-D">-D, --dump-header</a>!
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-B"></a><span class="nroffip">-B, --use-ascii</span>
+<p class="level1">(FTP/LDAP) Enable ASCII transfer. For FTP, this can also be enforced by using an URL that ends with ";type=A". This option causes data sent to stdout to be in text mode for win32 systems.
+<p class="level0"><a name="--basic"></a><span class="nroffip">--basic</span>
+<p class="level1">(HTTP) Tells curl to use HTTP Basic authentication. This is the default and this option is usually pointless, unless you use it to override a previously set option that sets a different authentication method (such as <a class="emphasis" href="#--ntlm">--ntlm</a>, <a class="emphasis" href="#--digest">--digest</a>, or <a class="emphasis" href="#--negotiate">--negotiate</a>).
+<p class="level0"><a name="-c"></a><span class="nroffip">-c, --cookie-jar &lt;file name&gt;</span>
+<p class="level1">(HTTP) Specify to which file you want curl to write all cookies after a completed operation. Curl writes all cookies previously read from a specified file as well as all cookies received from remote server(s). If no cookies are known, no file will be written. The file will be written using the Netscape cookie file format. If you set the file name to a single dash, "-", the cookies will be written to stdout.
+<p class="level1">This command line option will activate the cookie engine that makes curl record and use cookies. Another way to activate it is to use the <span class="emphasis">-b, --cookie</span> option.
+<p class="level1">If the cookie jar can't be created or written to, the whole curl operation won't fail or even report an error clearly. Using -v will get a warning displayed, but that is the only visible feedback you get about this possibly lethal situation.
+<p class="level1">If this option is used several times, the last specified file name will be used.
+<p class="level0"><a name="-C"></a><span class="nroffip">-C, --continue-at &lt;offset&gt;</span>
+<p class="level1">Continue/Resume a previous file transfer at the given offset. The given offset is the exact number of bytes that will be skipped, counting from the beginning of the source file before it is transferred to the destination. If used with uploads, the FTP server command SIZE will not be used by curl.
+<p class="level1">Use "-C -" to tell curl to automatically find out where/how to resume the transfer. It then uses the given output/input files to figure that out.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--ciphers"></a><span class="nroffip">--ciphers &lt;list of ciphers&gt;</span>
+<p class="level1">(SSL) Specifies which ciphers to use in the connection. The list of ciphers must specify valid ciphers. Read up on SSL cipher list details on this URL: <span Class="emphasis"><a href="http://www.openssl.org/docs/apps/ciphers.html">http://www.openssl.org/docs/apps/ciphers.html</a></span>
+<p class="level1">NSS ciphers are done differently than OpenSSL and GnuTLS. The full list of NSS ciphers is in the NSSCipherSuite entry at this URL: <span Class="emphasis"><a href="http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html">http://git.fedorahosted.org/cgit/mod_nss.git/plain/docs/mod_nss.html</a>#Directives</span>
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--compressed"></a><span class="nroffip">--compressed</span>
+<p class="level1">(HTTP) Request a compressed response using one of the algorithms curl supports, and save the uncompressed document. If this option is used and the server sends an unsupported encoding, curl will report an error.
+<p class="level0"><a name="--connect-timeout"></a><span class="nroffip">--connect-timeout &lt;seconds&gt;</span>
+<p class="level1">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. 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 <a class="emphasis" href="#-m">-m, --max-time</a> option.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--create-dirs"></a><span class="nroffip">--create-dirs</span>
+<p class="level1">When used in conjunction with the <a class="emphasis" href="#-o">-o</a> option, curl will create the necessary local directory hierarchy as needed. This option creates the dirs mentioned with the <a class="emphasis" href="#-o">-o</a> option, nothing else. If the <a class="emphasis" href="#-o">-o</a> file name uses no dir or if the dirs it mentions already exist, no dir will be created.
+<p class="level1">To create remote directories when using FTP or SFTP, try <a class="emphasis" href="#--ftp-create-dirs">--ftp-create-dirs</a>.
+<p class="level0"><a name="--crlf"></a><span class="nroffip">--crlf</span>
+<p class="level1">(FTP) Convert LF to CRLF in upload. Useful for MVS (OS/390).
+<p class="level0"><a name="--crlfile"></a><span class="nroffip">--crlfile &lt;file&gt;</span>
+<p class="level1">(HTTPS/FTPS) Provide a file using PEM format with a Certificate Revocation List that may specify peer certificates that are to be considered revoked.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level1">(Added in 7.19.7)
+<p class="level0"><a name="-d"></a><span class="nroffip">-d, --data &lt;data&gt;</span>
+<p class="level1">(HTTP) Sends the specified data in a POST request to the HTTP server, in the same way that a browser does when a user has filled in an HTML form and presses the submit button. This will cause curl to pass the data to the server using the content-type application/x-www-form-urlencoded. Compare to <a class="emphasis" href="#-F">-F, --form</a>.
+<p class="level1"><a class="emphasis" href="#-d">-d, --data</a> is the same as <a class="emphasis" href="#--data-ascii">--data-ascii</a>. To post data purely binary, you should instead use the <a class="emphasis" href="#--data-binary">--data-binary</a> option. To URL-encode the value of a form field you may use <a class="emphasis" href="#--data-urlencode">--data-urlencode</a>.
+<p class="level1">If any of these options is used more than once on the same command line, the data pieces specified will be merged together with a separating &-symbol. Thus, using '-d name=daniel -d skill=lousy' would generate a post chunk that looks like 'name=daniel&skill=lousy'.
+<p class="level1">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 <span Class="emphasis">--data</span> @foobar. When --data is told to read from a file like that, carriage returns and newlines will be stripped out.
+<p class="level0"><a name="-D"></a><span class="nroffip">-D, --dump-header &lt;file&gt;</span>
+<p class="level1">Write the protocol headers to the specified file.
+<p class="level1">This option is handy to use when you want to store the headers that an HTTP site sends to you. Cookies from the headers could then be read in a second curl invocation by using the <a class="emphasis" href="#-b">-b, --cookie</a> option! The <a class="emphasis" href="#-c">-c, --cookie-jar</a> option is however a better way to store cookies.
+<p class="level1">When used in FTP, the FTP server response lines are considered being "headers" and thus are saved there.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level1">
+<p class="level0"><a name="--data-ascii"></a><span class="nroffip">--data-ascii &lt;data&gt;</span>
+<p class="level1">See <a class="emphasis" href="#-d">-d, --data</a>.
+<p class="level0"><a name="--data-binary"></a><span class="nroffip">--data-binary &lt;data&gt;</span>
+<p class="level1">(HTTP) This posts data exactly as specified with no extra processing whatsoever.
+<p class="level1">If you start the data with the letter @, the rest should be a filename. Data is posted in a similar manner as <a class="emphasis" href="#--data-ascii">--data-ascii</a> does, except that newlines and carriage returns are preserved and conversions are never done.
+<p class="level1">If this option is used several times, the ones following the first will append data as described in <a class="emphasis" href="#-d">-d, --data</a>.
+<p class="level0"><a name="--data-urlencode"></a><span class="nroffip">--data-urlencode &lt;data&gt;</span>
+<p class="level1">(HTTP) This posts data, similar to the other --data options with the exception that this performs URL-encoding. (Added in 7.18.0)
+<p class="level1">To be CGI-compliant, the &lt;data&gt; part should begin with a <span Class="emphasis">name</span> followed by a separator and a content specification. The &lt;data&gt; part can be passed to curl using one of the following syntaxes:
+<p class="level2">
+<p class="level1"><a name="content"></a><span class="nroffip">content</span>
+<p class="level2">This will make curl URL-encode the content and pass that on. Just be careful so that the content doesn't contain any = or @ symbols, as that will then make the syntax match one of the other cases below!
+<p class="level1"><a name="content"></a><span class="nroffip">=content</span>
+<p class="level2">This will make curl URL-encode the content and pass that on. The preceding = symbol is not included in the data.
+<p class="level1"><a name="namecontent"></a><span class="nroffip">name=content</span>
+<p class="level2">This will make curl URL-encode the content part and pass that on. Note that the name part is expected to be URL-encoded already.
+<p class="level1"><a name="filename"></a><span class="nroffip">@filename</span>
+<p class="level2">This will make curl load data from the given file (including any newlines), URL-encode that data and pass it on in the POST.
+<p class="level1"><a name="namefilename"></a><span class="nroffip">name@filename</span>
+<p class="level2">This will make curl load data from the given file (including any newlines), URL-encode that data and pass it on in the POST. The name part gets an equal sign appended, resulting in <span Class="emphasis">name=urlencoded-file-content</span>. Note that the name is expected to be URL-encoded already.
+<p class="level1">
+<p class="level0"><a name="--delegation"></a><span class="nroffip">--delegation LEVEL</span>
+<p class="level1">Set <span Class="emphasis">LEVEL</span> to tell the server what it is allowed to delegate when it comes to user credentials. Used with GSS/kerberos.
+<p class="level2">
+<p class="level1"><a name="none"></a><span class="nroffip">none</span>
+<p class="level2">Don't allow any delegation.
+<p class="level1"><a name="policy"></a><span class="nroffip">policy</span>
+<p class="level2">Delegates if and only if the OK-AS-DELEGATE flag is set in the Kerberos service ticket, which is a matter of realm policy.
+<p class="level1"><a name="always"></a><span class="nroffip">always</span>
+<p class="level2">Unconditionally allow the server to delegate.
+<p class="level1">
+<p class="level0"><a name="--digest"></a><span class="nroffip">--digest</span>
+<p class="level1">(HTTP) Enables HTTP Digest authentication. This is an authentication scheme that prevents the password from being sent over the wire in clear text. Use this in combination with the normal <a class="emphasis" href="#-u">-u, --user</a> option to set user name and password. See also <a class="emphasis" href="#--ntlm">--ntlm</a>, <a class="emphasis" href="#--negotiate">--negotiate</a> and <a class="emphasis" href="#--anyauth">--anyauth</a> for related options.
+<p class="level1">If this option is used several times, only the first one is used.
+<p class="level0"><a name="--disable-eprt"></a><span class="nroffip">--disable-eprt</span>
+<p class="level1">(FTP) Tell curl to disable the use of the EPRT and LPRT commands when doing active FTP transfers. Curl will normally always first attempt to use EPRT, then LPRT before using PORT, but with this option, it will use PORT right away. EPRT and LPRT are extensions to the original FTP protocol, and may not work on all servers, but they enable more functionality in a better way than the traditional PORT command.
+<p class="level1"><span Class="bold">--eprt</span> can be used to explicitly enable EPRT again and <span Class="bold">--no-eprt</span> is an alias for <a class="bold" href="#--disable-eprt">--disable-eprt</a>.
+<p class="level1">Disabling EPRT only changes the active behavior. If you want to switch to passive mode you need to not use <a class="emphasis" href="#-P">-P, --ftp-port</a> or force it with <a class="emphasis" href="#--ftp-pasv">--ftp-pasv</a>.
+<p class="level0"><a name="--disable-epsv"></a><span class="nroffip">--disable-epsv</span>
+<p class="level1">(FTP) Tell curl to disable the use of the EPSV command when doing passive FTP transfers. Curl will normally always first attempt to use EPSV before PASV, but with this option, it will not try using EPSV.
+<p class="level1"><span Class="bold">--epsv</span> can be used to explicitly enable EPSV again and <span Class="bold">--no-epsv</span> is an alias for <a class="bold" href="#--disable-epsv">--disable-epsv</a>.
+<p class="level1">Disabling EPSV only changes the passive behavior. If you want to switch to active mode you need to use <a class="emphasis" href="#-P">-P, --ftp-port</a>.
+<p class="level0"><a name="--dns-interface"></a><span class="nroffip">--dns-interface &lt;interface&gt;</span>
+<p class="level1">Tell curl to send outgoing DNS requests through &lt;interface&gt;. This option is a counterpart to <a class="emphasis" href="#--interface">--interface</a> (which does not affect DNS). The supplied string must be an interface name (not an address).
+<p class="level1">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)
+<p class="level0"><a name="--dns-ipv4-addr"></a><span class="nroffip">--dns-ipv4-addr &lt;ip-address&gt;</span>
+<p class="level1">Tell curl to bind to &lt;ip-address&gt; when making IPv4 DNS requests, so that the DNS requests originate from this address. The argument should be a single IPv4 address.
+<p class="level1">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)
+<p class="level0"><a name="--dns-ipv6-addr"></a><span class="nroffip">--dns-ipv6-addr &lt;ip-address&gt;</span>
+<p class="level1">Tell curl to bind to &lt;ip-address&gt; when making IPv6 DNS requests, so that the DNS requests originate from this address. The argument should be a single IPv6 address.
+<p class="level1">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)
+<p class="level0"><a name="--dns-servers"></a><span class="nroffip">--dns-servers &lt;ip-address,ip-address&gt;</span>
+<p class="level1">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 <span Class="emphasis">:&lt;port-number&gt;</span> after each IP address.
+<p class="level1">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)
+<p class="level0"><a name="-e"></a><span class="nroffip">-e, --referer &lt;URL&gt;</span>
+<p class="level1">(HTTP) Sends the "Referer Page" information to the HTTP server. This can also be set with the <a class="emphasis" href="#-H">-H, --header</a> flag of course. When used with <a class="emphasis" href="#-L">-L, --location</a> you can append ";auto" to the --referer URL to make curl automatically set the previous URL when it follows a Location: header. The ";auto" string can be used alone, even if you don't set an initial --referer.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-E"></a><span class="nroffip">-E, --cert &lt;certificate[:password]&gt;</span>
+<p class="level1">(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 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 <span Class="emphasis">--cert</span> and <a class="emphasis" href="#--key">--key</a> to specify them independently.
+<p class="level1">If curl is built against the NSS SSL library then this option can tell 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. 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.
+<p class="level1">(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.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--engine"></a><span class="nroffip">--engine &lt;name&gt;</span>
+<p class="level1">Select the OpenSSL crypto engine to use for cipher operations. Use <a class="emphasis" href="#--engine">--engine list</a> to print a list of build-time supported engines. Note that not all (or none) of the engines may be available at run-time.
+<p class="level0"><a name="--environment"></a><span class="nroffip">--environment</span>
+<p class="level1">(RISC OS ONLY) Sets a range of environment variables, using the names the <a class="emphasis" href="#-w">-w</a> option supports, to allow easier extraction of useful information after having run curl.
+<p class="level0"><a name="--egd-file"></a><span class="nroffip">--egd-file &lt;file&gt;</span>
+<p class="level1">(SSL) Specify the path name to the Entropy Gathering Daemon socket. The socket is used to seed the random engine for SSL connections. See also the <a class="emphasis" href="#--random-file">--random-file</a> option.
+<p class="level0"><a name="--cert-type"></a><span class="nroffip">--cert-type &lt;type&gt;</span>
+<p class="level1">(SSL) Tells curl what certificate type the provided certificate is in. PEM, DER and ENG are recognized types. If not specified, PEM is assumed.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--cacert"></a><span class="nroffip">--cacert &lt;CA certificate&gt;</span>
+<p class="level1">(SSL) Tells curl to use the specified certificate file to verify the peer. The file may contain multiple CA certificates. The certificate(s) must be in PEM format. Normally curl is built to use a default file for this, so this option is typically used to alter that default file.
+<p class="level1">curl recognizes the environment variable named 'CURL_CA_BUNDLE' if it is set, and uses the given path as a path to a CA cert bundle. This option overrides that variable.
+<p class="level1">The windows version of curl will automatically look for a CA certs file named &acute;curl-ca-bundle.crt&acute;, either in the same directory as curl.exe, or in the Current Working Directory, or in any folder along your PATH.
+<p class="level1">If curl is built against the NSS SSL library, the NSS PEM PKCS#11 module (libnsspem.so) needs to be available for this option to work properly.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--capath"></a><span class="nroffip">--capath &lt;CA certificate directory&gt;</span>
+<p class="level1">(SSL) Tells curl to use the specified certificate directory to verify the peer. Multiple paths can be provided by separating them with ":" (e.g. "path1:path2:path3"). The certificates must be in PEM format, and if curl is built against OpenSSL, the directory must have been processed using the c_rehash utility supplied with OpenSSL. Using <a class="emphasis" href="#--capath">--capath</a> can allow OpenSSL-powered curl to make SSL-connections much more efficiently than using <a class="emphasis" href="#--cacert">--cacert</a> if the <a class="emphasis" href="#--cacert">--cacert</a> file contains many CA certificates.
+<p class="level1">If this option is set, the default capath value will be ignored, and if it is used several times, the last one will be used.
+<p class="level0"><a name="-f"></a><span class="nroffip">-f, --fail</span>
+<p class="level1">(HTTP) Fail silently (no output at all) on server errors. This is mostly done to better enable scripts etc to better deal with failed attempts. In normal cases when an HTTP server fails to deliver a document, it returns an HTML document stating so (which often also describes why and more). This flag will prevent curl from outputting that and return error 22.
+<p class="level1">This method is not fail-safe and there are occasions where non-successful response codes will slip through, especially when authentication is involved (response codes 401 and 407).
+<p class="level0"><a name="-F"></a><span class="nroffip">-F, --form &lt;name=content&gt;</span>
+<p class="level1">(HTTP) This lets curl emulate a filled-in form in which a user has pressed the submit button. This causes curl to POST data using the Content-Type multipart/form-data according to <a href="http://www.ietf.org/rfc/rfc2388.txt">RFC 2388</a>. This enables uploading of binary files etc. To force the 'content' part to be a file, prefix the file name with an @ sign. To just get the content part from a file, prefix the file name with the symbol &lt;. The difference between @ and &lt; is then that @ makes a file get attached in the post as a file upload, while the &lt; makes a text field and just get the contents for that text field from a file.
+<p class="level1">Example, to send your password file to the server, where 'password' is the name of the form-field to which /etc/passwd will be the input:
+<p class="level1"><span Class="bold">curl</span> -F password=@/etc/passwd www.mypasswords.com
+<p class="level1">To read content from stdin instead of a file, use - as the filename. This goes for both @ and &lt; constructs.
+<p class="level1">You can also tell curl what Content-Type to use by using 'type=', in a manner similar to:
+<p class="level1"><span Class="bold">curl</span> -F "web=@index.html;type=text/html" url.com
+<p class="level1">or
+<p class="level1"><span Class="bold">curl</span> -F "name=daniel;type=text/foo" url.com
+<p class="level1">You can also explicitly change the name field of a file upload part by setting filename=, like this:
+<p class="level1"><span Class="bold">curl</span> -F "file=@localfile;filename=nameinpost" url.com
+<p class="level1">If filename/path contains ',' or ';', it must be quoted by double-quotes like:
+<p class="level1"><span Class="bold">curl</span> -F "file=@\"localfile\";filename=\"nameinpost\"" url.com
+<p class="level1">or
+<p class="level1"><span Class="bold">curl</span> -F 'file=@"localfile";filename="nameinpost"' url.com
+<p class="level1">Note that if a filename/path is quoted by double-quotes, any double-quote or backslash within the filename must be escaped by backslash.
+<p class="level1">See further examples and details in the MANUAL.
+<p class="level1">This option can be used multiple times.
+<p class="level0"><a name="--ftp-account"></a><span class="nroffip">--ftp-account [data]</span>
+<p class="level1">(FTP) When an FTP server asks for "account data" after user name and password has been provided, this data is sent off using the ACCT command. (Added in 7.13.0)
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--ftp-alternative-to-user"></a><span class="nroffip">--ftp-alternative-to-user &lt;command&gt;</span>
+<p class="level1">(FTP) If authenticating with the USER and PASS commands fails, send this command. When connecting to Tumbleweed's Secure Transport server over FTPS using a client certificate, using "SITE AUTH" will tell the server to retrieve the username from the certificate. (Added in 7.15.5)
+<p class="level0"><a name="--ftp-create-dirs"></a><span class="nroffip">--ftp-create-dirs</span>
+<p class="level1">(FTP/SFTP) When an FTP or SFTP URL/operation uses a path that doesn't currently exist on the server, the standard behavior of curl is to fail. Using this option, curl will instead attempt to create missing directories.
+<p class="level0"><a name="--ftp-method"></a><span class="nroffip">--ftp-method [method]</span>
+<p class="level1">(FTP) Control what method curl should use to reach a file on an FTP(S) server. The method argument should be one of the following alternatives:
+<p class="level2">
+<p class="level1"><a name="multicwd"></a><span class="nroffip">multicwd</span>
+<p class="level2">curl does a single CWD operation for each path part in the given URL. For deep hierarchies this means very many commands. This is how <a href="http://www.ietf.org/rfc/rfc1738.txt">RFC 1738</a> says it should be done. This is the default but the slowest behavior.
+<p class="level1"><a name="nocwd"></a><span class="nroffip">nocwd</span>
+<p class="level2">curl does no CWD at all. curl will do SIZE, RETR, STOR etc and give a full path to the server for all these commands. This is the fastest behavior.
+<p class="level1"><a name="singlecwd"></a><span class="nroffip">singlecwd</span>
+<p class="level2">curl does one CWD with the full target directory and then operates on the file "normally" (like in the multicwd case). This is somewhat more standards compliant than 'nocwd' but without the full penalty of 'multicwd'.
+<p class="level1">(Added in 7.15.1)
+<p class="level0"><a name="--ftp-pasv"></a><span class="nroffip">--ftp-pasv</span>
+<p class="level1">(FTP) Use passive mode for the data connection. Passive is the internal default behavior, but using this option can be used to override a previous <span Class="emphasis">-P/-ftp-port</span> option. (Added in 7.11.0)
+<p class="level1">If this option is used several times, only the first one is used. Undoing an enforced passive really isn't doable but you must then instead enforce the correct <a class="emphasis" href="#-P">-P, --ftp-port</a> again.
+<p class="level1">Passive mode means that curl will try the EPSV command first and then PASV, unless <a class="emphasis" href="#--disable-epsv">--disable-epsv</a> is used.
+<p class="level0"><a name="--ftp-skip-pasv-ip"></a><span class="nroffip">--ftp-skip-pasv-ip</span>
+<p class="level1">(FTP) Tell curl to not use the IP address the server suggests in its response to curl's PASV command when curl connects the data connection. Instead curl will re-use the same IP address it already uses for the control connection. (Added in 7.14.2)
+<p class="level1">This option has no effect if PORT, EPRT or EPSV is used instead of PASV.
+<p class="level0"><a name="--ftp-pret"></a><span class="nroffip">--ftp-pret</span>
+<p class="level1">(FTP) Tell curl to send a PRET command before PASV (and EPSV). Certain FTP servers, mainly drftpd, require this non-standard command for directory listings as well as up and downloads in PASV mode. (Added in 7.20.x)
+<p class="level0"><a name="--ftp-ssl-ccc"></a><span class="nroffip">--ftp-ssl-ccc</span>
+<p class="level1">(FTP) Use CCC (Clear Command Channel) Shuts down the SSL/TLS layer after authenticating. The rest of the control channel communication will be unencrypted. This allows NAT routers to follow the FTP transaction. The default mode is passive. See <a class="emphasis" href="#--ftp-ssl-ccc-mode">--ftp-ssl-ccc-mode</a> for other modes. (Added in 7.16.1)
+<p class="level0"><a name="--ftp-ssl-ccc-mode"></a><span class="nroffip">--ftp-ssl-ccc-mode [active/passive]</span>
+<p class="level1">(FTP) Use CCC (Clear Command Channel) Sets the CCC mode. The passive mode will not initiate the shutdown, but instead wait for the server to do it, and will not reply to the shutdown from the server. The active mode initiates the shutdown and waits for a reply from the server. (Added in 7.16.2)
+<p class="level0"><a name="--ftp-ssl-control"></a><span class="nroffip">--ftp-ssl-control</span>
+<p class="level1">(FTP) Require SSL/TLS for the FTP login, clear for transfer. Allows secure authentication, but non-encrypted data transfers for efficiency. Fails the transfer if the server doesn't support SSL/TLS. (Added in 7.16.0) that can still be used but will be removed in a future version.
+<p class="level0"><a name="--form-string"></a><span class="nroffip">--form-string &lt;name=string&gt;</span>
+<p class="level1">(HTTP) Similar to <span Class="emphasis">--form</span> except that the value string for the named parameter is used literally. Leading '@' and '&lt;' characters, and the ';type=' string in the value have no special meaning. Use this in preference to <span Class="emphasis">--form</span> if there's any possibility that the string value may accidentally trigger the '@' or '&lt;' features of <span Class="emphasis">--form</span>.
+<p class="level0"><a name="-g"></a><span class="nroffip">-g, --globoff</span>
+<p class="level1">This option switches off the "URL globbing parser". When you set this option, you can specify URLs that contain the letters {}[] without having them being interpreted by curl itself. Note that these letters are not normal legal URL contents but they should be encoded according to the URI standard.
+<p class="level0"><a name="-G"></a><span class="nroffip">-G, --get</span>
+<p class="level1">When used, this option will make all data specified with <a class="emphasis" href="#-d">-d, --data</a> or <a class="emphasis" href="#--data-binary">--data-binary</a> to be used in an HTTP GET request instead of the POST request that otherwise would be used. The data will be appended to the URL with a '?' separator.
+<p class="level1">If used in combination with -I, the POST data will instead be appended to the URL with a HEAD request.
+<p class="level1">If this option is used several times, only the first one is used. This is because undoing a GET doesn't make sense, but you should then instead enforce the alternative method you prefer.
+<p class="level0"><a name="-H"></a><span class="nroffip">-H, --header &lt;header&gt;</span>
+<p class="level1">(HTTP) Extra header to use when getting a web page. You may specify any number of extra headers. Note that if you should add a custom header that has the same name as one of the internal ones curl would use, your externally set header will be used instead of the internal one. This allows you to make even trickier stuff than curl would normally do. You should not replace internally set headers without knowing perfectly well what you're doing. Remove an internal header by giving a replacement without content on the right side of the colon, as in: -H "Host:". If you send the custom header with no-value then its header must be terminated with a semicolon, such as -H "X-Custom-Header;" to send "X-Custom-Header:".
+<p class="level1">curl will make sure that each header you add/replace is sent with the proper end-of-line marker, you should thus <span Class="bold">not</span> add that as a part of the header content: do not add newlines or carriage returns, they will only mess things up for you.
+<p class="level1">See also the <a class="emphasis" href="#-A">-A, --user-agent</a> and <a class="emphasis" href="#-e">-e, --referer</a> options.
+<p class="level1">This option can be used multiple times to add/replace/remove multiple headers.
+<p class="level0"><a name="--hostpubmd5"></a><span class="nroffip">--hostpubmd5 &lt;md5&gt;</span>
+<p class="level1">(SCP/SFTP) Pass a string containing 32 hexadecimal digits. The string should be the 128 bit MD5 checksum of the remote host's public key, curl will refuse the connection with the host unless the md5sums match. (Added in 7.17.1)
+<p class="level0"><a name="--ignore-content-length"></a><span class="nroffip">--ignore-content-length</span>
+<p class="level1">(HTTP) Ignore the Content-Length header. This is particularly useful for servers running Apache 1.x, which will report incorrect Content-Length for files larger than 2 gigabytes.
+<p class="level0"><a name="-i"></a><span class="nroffip">-i, --include</span>
+<p class="level1">(HTTP) Include the HTTP-header in the output. The HTTP-header includes things like server-name, date of the document, HTTP-version and more...
+<p class="level0"><a name="-I"></a><span class="nroffip">-I, --head</span>
+<p class="level1">(HTTP/FTP/FILE) Fetch the HTTP-header only! HTTP-servers feature the command HEAD which this uses to get nothing but the header of a document. When used on an FTP or FILE file, curl displays the file size and last modification time only.
+<p class="level0"><a name="--interface"></a><span class="nroffip">--interface &lt;name&gt;</span>
+<p class="level1">Perform an operation using a specified interface. You can enter interface name, IP address or host name. An example could look like:
+<p class="level1">&nbsp;curl --interface eth0:1 <a href="http://www.netscape.com/">http://www.netscape.com/</a>
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-j"></a><span class="nroffip">-j, --junk-session-cookies</span>
+<p class="level1">(HTTP) When curl is told to read cookies from a given file, this option will make it discard all "session cookies". This will basically have the same effect as if a new session is started. Typical browsers always discard session cookies when they're closed down.
+<p class="level0"><a name="-J"></a><span class="nroffip">-J, --remote-header-name</span>
+<p class="level1">(HTTP) This option tells the <a class="emphasis" href="#-O">-O, --remote-name</a> option to use the server-specified Content-Disposition filename instead of extracting a filename from the URL.
+<p class="level0"><a name="-k"></a><span class="nroffip">-k, --insecure</span>
+<p class="level1">(SSL) This option explicitly allows curl to perform "insecure" SSL connections and transfers. All SSL connections are attempted to be made secure by using the CA certificate bundle installed by default. This makes all connections considered "insecure" fail unless <a class="emphasis" href="#-k">-k, --insecure</a> is used.
+<p class="level1">See this online resource for further details: <span Class="bold"><a href="http://curl.haxx.se/docs/sslcerts.html">http://curl.haxx.se/docs/sslcerts.html</a></span>
+<p class="level0"><a name="-K"></a><span class="nroffip">-K, --config &lt;config file&gt;</span>
+<p class="level1">Specify which config file to read curl arguments from. The config file is a text file in which command line arguments can be written which then will be used as if they were written on the actual command line. Options and their parameters must be specified on the same config file line, separated by whitespace, colon, the equals sign or any combination thereof (however, the preferred separator is the equals sign). If the parameter is to contain whitespace, the parameter must be enclosed within quotes. Within double quotes, the following escape sequences are available: \\, \", \t, \n, \r and \v. A backslash preceding any other letter is ignored. If the first column of a config line is a '#' character, the rest of the line will be treated as a comment. Only write one option per physical line in the config file.
+<p class="level1">Specify the filename to -K, --config as '-' to make curl read the file from stdin.
+<p class="level1">Note that to be able to specify a URL in the config file, you need to specify it using the <a class="emphasis" href="#--url">--url</a> option, and not by simply writing the URL on its own line. So, it could look similar to this:
+<p class="level1">url = "<a href="http://curl.haxx.se/docs/">http://curl.haxx.se/docs/</a>"
+<p class="level1">Long option names can optionally be given in the config file without the initial double dashes.
+<p class="level1">When curl is invoked, it always (unless <a class="emphasis" href="#-q">-q</a> is used) checks for a default config file and uses it if found. The default config file is checked for in the following places in this order:
+<p class="level1">1) curl tries to find the "home dir": It first checks for the CURL_HOME and then the HOME environment variables. Failing that, it uses getpwuid() on UNIX-like systems (which returns the home dir given the current user in your system). On Windows, it then checks for the APPDATA variable, or as a last resort the '%USERPROFILE%\Application Data'.
+<p class="level1">2) On windows, if there is no _curlrc file in the home dir, it checks for one in the same dir the curl executable is placed. On UNIX-like systems, it will simply try to load .curlrc from the determined home dir.
+<p class="level1"><pre>
+<p class="level1"># --- Example file ---
+ # this is a comment
+ url = "curl.haxx.se"
+ output = "curlhere.html"
+ user-agent = "superagent/1.0"
+ <p class="level1"># and fetch another URL too
+ url = "curl.haxx.se/docs/manpage.html"
+ -O
+ referer = "<a href="http://nowhereatall.com/">http://nowhereatall.com/</a>"
+ # --- End of example file ---
+ </pre>
+
+<p class="level1">
+<p class="level1">This option can be used multiple times to load multiple config files.
+<p class="level0"><a name="--keepalive-time"></a><span class="nroffip">--keepalive-time &lt;seconds&gt;</span>
+<p class="level1">This option sets the time a connection needs to remain idle before sending keepalive probes and the time between individual keepalive probes. It is currently effective on operating systems offering the TCP_KEEPIDLE and TCP_KEEPINTVL socket options (meaning Linux, recent AIX, HP-UX and more). This option has no effect if <a class="emphasis" href="#--no-keepalive">--no-keepalive</a> is used. (Added in 7.18.0)
+<p class="level1">If this option is used several times, the last one will be used. If unspecified, the option defaults to 60 seconds.
+<p class="level0"><a name="--key"></a><span class="nroffip">--key &lt;key&gt;</span>
+<p class="level1">(SSL/SSH) Private key file name. Allows you to provide your private key in this separate file.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--key-type"></a><span class="nroffip">--key-type &lt;type&gt;</span>
+<p class="level1">(SSL) Private key file type. Specify which type your <a class="emphasis" href="#--key">--key</a> provided private key is. DER, PEM, and ENG are supported. If not specified, PEM is assumed.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--krb"></a><span class="nroffip">--krb &lt;level&gt;</span>
+<p class="level1">(FTP) Enable Kerberos authentication and use. The level must be entered and should be one of 'clear', 'safe', 'confidential', or 'private'. Should you use a level that is not one of these, 'private' will instead be used.
+<p class="level1">This option requires a library built with kerberos4 or GSSAPI (GSS-Negotiate) support. This is not very common. Use <a class="emphasis" href="#-V">-V, --version</a> to see if your curl supports it.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-l"></a><span class="nroffip">-l, --list-only</span>
+<p class="level1">(FTP) When listing an FTP directory, this switch forces a name-only view. Especially useful if you want to machine-parse the contents of an FTP directory since the normal directory view doesn't use a standard look or format.
+<p class="level1">This option causes an FTP NLST command to be sent. Some FTP servers list only files in their response to NLST; they do not include subdirectories and symbolic links.
+<p class="level1">
+<p class="level0"><a name="-L"></a><span class="nroffip">-L, --location</span>
+<p class="level1">(HTTP/HTTPS) If the server reports that the requested page has moved to a different location (indicated with a Location: header and a 3XX response code), this option will make curl redo the request on the new place. If used together with <a class="emphasis" href="#-i">-i, --include</a> or <a class="emphasis" href="#-I">-I, --head</a>, headers from all requested pages will be shown. When authentication is used, curl only sends its credentials to the initial host. If a redirect takes curl to a different host, it won't be able to intercept the user+password. See also <a class="emphasis" href="#--location-trusted">--location-trusted</a> on how to change this. You can limit the amount of redirects to follow by using the <a class="emphasis" href="#--max-redirs">--max-redirs</a> option.
+<p class="level1">When curl follows a redirect and the request is not a plain GET (for example POST or PUT), it will do the following request with a GET if the HTTP response was 301, 302, or 303. If the response code was any other 3xx code, curl will re-send the following request using the same unmodified method.
+<p class="level0"><a name="--libcurl"></a><span class="nroffip">--libcurl &lt;file&gt;</span>
+<p class="level1">Append this option to any ordinary curl command line, and you will get a libcurl-using C source code written to the file that does the equivalent of what your command-line operation does!
+<p class="level1">If this option is used several times, the last given file name will be used. (Added in 7.16.1)
+<p class="level0"><a name="--limit-rate"></a><span class="nroffip">--limit-rate &lt;speed&gt;</span>
+<p class="level1">Specify the maximum transfer rate you want curl to use. This feature is useful if you have a limited pipe and you'd like your transfer not to use your entire bandwidth.
+<p class="level1">The given speed is measured in bytes/second, unless a suffix is appended. Appending 'k' or 'K' will count the number as kilobytes, 'm' or M' makes it megabytes, while 'g' or 'G' makes it gigabytes. Examples: 200K, 3m and 1G.
+<p class="level1">The given rate is the average speed counted during the entire transfer. It means that curl might use higher transfer speeds in short bursts, but over time it uses no more than the given rate.
+<p class="level1">If you also use the <a class="emphasis" href="#-Y">-Y, --speed-limit</a> option, that option will take precedence and might cripple the rate-limiting slightly, to help keeping the speed-limit logic working.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--local-port"></a><span class="nroffip">--local-port &lt;num&gt;[-num]</span>
+<p class="level1">Set a preferred number or range of local port numbers to use for the connection(s). Note that port numbers by nature are a scarce resource that will be busy at times so setting this range to something too narrow might cause unnecessary connection setup failures. (Added in 7.15.2)
+<p class="level0"><a name="--location-trusted"></a><span class="nroffip">--location-trusted</span>
+<p class="level1">(HTTP/HTTPS) Like <a class="emphasis" href="#-L">-L, --location</a>, but will allow sending the name + password to all hosts that the site may redirect to. This may or may not introduce a security breach if the site redirects you to a site to which you'll send your authentication info (which is plaintext in the case of HTTP Basic authentication).
+<p class="level0"><a name="-m"></a><span class="nroffip">-m, --max-time &lt;seconds&gt;</span>
+<p class="level1">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. 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 <a class="emphasis" href="#--connect-timeout">--connect-timeout</a> option.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--mail-auth"></a><span class="nroffip">--mail-auth &lt;address&gt;</span>
+<p class="level1">(SMTP) Specify a single address. This will be used to specify the authentication address (identity) of a submitted message that is being relayed to another server.
+<p class="level1">(Added in 7.25.0)
+<p class="level0"><a name="--mail-from"></a><span class="nroffip">--mail-from &lt;address&gt;</span>
+<p class="level1">(SMTP) Specify a single address that the given mail should get sent from.
+<p class="level1">(Added in 7.20.0)
+<p class="level0"><a name="--max-filesize"></a><span class="nroffip">--max-filesize &lt;bytes&gt;</span>
+<p class="level1">Specify the maximum size (in bytes) of a file to download. If the file requested is larger than this value, the transfer will not start and curl will return with exit code 63.
+<p class="level1"><span Class="bold">NOTE:</span> The file size is not always known prior to download, and for such files this option has no effect even if the file transfer ends up being larger than this given limit. This concerns both FTP and HTTP transfers.
+<p class="level0"><a name="--mail-rcpt"></a><span class="nroffip">--mail-rcpt &lt;address&gt;</span>
+<p class="level1">(SMTP) Specify a single address that the given mail should get sent to. This option can be used multiple times to specify many recipients.
+<p class="level1">(Added in 7.20.0)
+<p class="level0"><a name="--max-redirs"></a><span class="nroffip">--max-redirs &lt;num&gt;</span>
+<p class="level1">Set maximum number of redirection-followings allowed. If <a class="emphasis" href="#-L">-L, --location</a> is used, this option can be used to prevent curl from following redirections "in absurdum". By default, the limit is set to 50 redirections. Set this option to -1 to make it limitless.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--metalink"></a><span class="nroffip">--metalink</span>
+<p class="level1">This option can tell curl to parse and process a given URI as Metalink file (both version 3 and 4 (<a href="http://www.ietf.org/rfc/rfc5854.txt">RFC 5854</a>) are supported) and make use of the mirrors listed within for failover if there are errors (such as the file or server not being available). It will also verify the hash of the file after the download completes. The Metalink file itself is downloaded and processed in memory and not stored in the local file system.
+<p class="level1">Example to use a remote Metalink file:
+<p class="level1"><span Class="bold">curl</span> --metalink <a href="http://www.example.com/example.metalink">http://www.example.com/example.metalink</a>
+<p class="level1">To use a Metalink file in the local file system, use FILE protocol (file://):
+<p class="level1"><span Class="bold">curl</span> --metalink file://example.metalink
+<p class="level1">Please note that if FILE protocol is disabled, there is no way to use a local Metalink file at the time of this writing. Also note that if <a class="emphasis" href="#--metalink">--metalink</a> and <span Class="emphasis">--include</span> are used together, <span Class="emphasis">--include</span> will be ignored. This is because including headers in the response will break Metalink parser and if the headers are included in the file described in Metalink file, hash check will fail.
+<p class="level1">(Added in 7.27.0, if built against the libmetalink library.)
+<p class="level0"><a name="-n"></a><span class="nroffip">-n, --netrc</span>
+<p class="level1">Makes curl scan the <span Class="emphasis">.netrc</span> (<span Class="emphasis">_netrc</span> on Windows) file in the user's home directory for login name and password. This is typically used for FTP on UNIX. If used with HTTP, curl will enable user authentication. See <span Class="manpage">netrc(4)</span> or <span Class="manpage">ftp(1)</span> for details on the file format. Curl will not complain if that file doesn't have the right permissions (it should not be either world- or group-readable). The environment variable "HOME" is used to find the home directory.
+<p class="level1">A quick and very simple example of how to setup a <span Class="emphasis">.netrc</span> to allow curl to FTP to the machine host.domain.com with user name 'myself' and password 'secret' should look similar to:
+<p class="level1"><span Class="bold">machine host.domain.com login myself password secret</span>
+<p class="level0"><a name="-N"></a><span class="nroffip">-N, --no-buffer</span>
+<p class="level1">Disables the buffering of the output stream. In normal work situations, curl will use a standard buffered output stream that will have the effect that it will output the data in chunks, not necessarily exactly when the data arrives. Using this option will disable that buffering.
+<p class="level1">Note that this is the negated option name documented. You can thus use <span Class="emphasis">--buffer</span> to enforce the buffering.
+<p class="level0"><a name="--netrc-file"></a><span class="nroffip">--netrc-file</span>
+<p class="level1">This option is similar to <span Class="emphasis">--netrc</span>, except that you provide the path (absolute or relative) to the netrc file that Curl should use. You can only specify one netrc file per invocation. If several <a class="emphasis" href="#--netrc-file">--netrc-file</a> options are provided, only the <span Class="bold">last one</span> will be used. (Added in 7.21.5)
+<p class="level1">This option overrides any use of <span Class="emphasis">--netrc</span> as they are mutually exclusive. It will also abide by <a class="emphasis" href="#--netrc-optional">--netrc-optional</a> if specified.
+<p class="level1">
+<p class="level0"><a name="--netrc-optional"></a><span class="nroffip">--netrc-optional</span>
+<p class="level1">Very similar to <span Class="emphasis">--netrc</span>, but this option makes the .netrc usage <span Class="bold">optional</span> and not mandatory as the <span Class="emphasis">--netrc</span> option does.
+<p class="level1">
+<p class="level0"><a name="--negotiate"></a><span class="nroffip">--negotiate</span>
+<p class="level1">(HTTP) Enables GSS-Negotiate authentication. The GSS-Negotiate method was designed by Microsoft and is used in their web applications. It is primarily meant as a support for Kerberos5 authentication but may be also used along with another authentication method. For more information see IETF draft draft-brezak-spnego-http-04.txt.
+<p class="level1">If you want to enable Negotiate for your proxy authentication, then use <a class="emphasis" href="#--proxy-negotiate">--proxy-negotiate</a>.
+<p class="level1">This option requires a library built with GSSAPI support. This is not very common. Use <a class="emphasis" href="#-V">-V, --version</a> to see if your version supports GSS-Negotiate.
+<p class="level1">When using this option, you must also provide a fake <a class="emphasis" href="#-u">-u, --user</a> option to activate the authentication code properly. Sending a '-u :' is enough as the user name and password from the <a class="emphasis" href="#-u">-u</a> option aren't actually used.
+<p class="level1">If this option is used several times, only the first one is used.
+<p class="level0"><a name="--no-keepalive"></a><span class="nroffip">--no-keepalive</span>
+<p class="level1">Disables the use of keepalive messages on the TCP connection, as by default curl enables them.
+<p class="level1">Note that this is the negated option name documented. You can thus use <span Class="emphasis">--keepalive</span> to enforce keepalive.
+<p class="level0"><a name="--no-sessionid"></a><span class="nroffip">--no-sessionid</span>
+<p class="level1">(SSL) Disable curl's use of SSL session-ID caching. By default all transfers are done using the cache. Note that while nothing should ever get hurt by attempting to reuse SSL session-IDs, there seem to be broken SSL implementations in the wild that may require you to disable this in order for you to succeed. (Added in 7.16.0)
+<p class="level1">Note that this is the negated option name documented. You can thus use <span Class="emphasis">--sessionid</span> to enforce session-ID caching.
+<p class="level0"><a name="--noproxy"></a><span class="nroffip">--noproxy &lt;no-proxy-list&gt;</span>
+<p class="level1">Comma-separated list of hosts which do not use a proxy, if one is specified. The only wildcard is a single * character, which matches all hosts, and effectively disables the proxy. Each name in this list is matched as either a domain which contains the hostname, or the hostname itself. For example, local.com would match local.com, local.com:80, and www.local.com, but not www.notlocal.com. (Added in 7.19.4).
+<p class="level0"><a name="--ntlm"></a><span class="nroffip">--ntlm</span>
+<p class="level1">(HTTP) Enables NTLM authentication. The NTLM authentication method was designed by Microsoft and is used by IIS web servers. It is a proprietary protocol, reverse-engineered by clever people and implemented in curl based on their efforts. This kind of behavior should not be endorsed, you should encourage everyone who uses NTLM to switch to a public and documented authentication method instead, such as Digest.
+<p class="level1">If you want to enable NTLM for your proxy authentication, then use <a class="emphasis" href="#--proxy-ntlm">--proxy-ntlm</a>.
+<p class="level1">This option requires a library built with SSL support. Use <a class="emphasis" href="#-V">-V, --version</a> to see if your curl supports NTLM.
+<p class="level1">If this option is used several times, only the first one is used.
+<p class="level0"><a name="-o"></a><span class="nroffip">-o, --output &lt;file&gt;</span>
+<p class="level1">Write output to &lt;file&gt; instead of stdout. If you are using {} or [] to fetch multiple documents, you can use '#' followed by a number in the &lt;file&gt; specifier. That variable will be replaced with the current string for the URL being fetched. Like in:
+<p class="level1">&nbsp; curl http://{one,two}.site.com -o "file_#1.txt"
+<p class="level1">or use several variables like:
+<p class="level1">&nbsp; curl http://{site,host}.host[1-5].com -o "#1_#2"
+<p class="level1">You may use this option as many times as the number of URLs you have.
+<p class="level1">See also the <a class="emphasis" href="#--create-dirs">--create-dirs</a> option to create the local directories dynamically. Specifying the output as '-' (a single dash) will force the output to be done to stdout.
+<p class="level0"><a name="-O"></a><span class="nroffip">-O, --remote-name</span>
+<p class="level1">Write output to a local file named like the remote file we get. (Only the file part of the remote file is used, the path is cut off.)
+<p class="level1">The remote file name to use for saving is extracted from the given URL, nothing else.
+<p class="level1">Consequentially, the file will be saved in the current working directory. If you want the file saved in a different directory, make sure you change current working directory before you invoke curl with the <a class="bold" href="#-O">-O, --remote-name</a> flag!
+<p class="level1">You may use this option as many times as the number of URLs you have.
+<p class="level0"><a name="--oauth2-bearer"></a><span class="nroffip">--oauth2-bearer</span>
+<p class="level1">(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 <a class="emphasis" href="#--url">--url</a> or <a class="emphasis" href="#-u">-u, --user</a> options.
+<p class="level1">The Bearer Token and user name are formatted according to <a href="http://www.ietf.org/rfc/rfc6750.txt">RFC 6750</a>.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-p"></a><span class="nroffip">-p, --proxytunnel</span>
+<p class="level1">When an HTTP proxy is used (<a class="emphasis" href="#-x">-x, --proxy</a>), this option will cause non-HTTP protocols to attempt to tunnel through the proxy instead of merely using it to do HTTP-like operations. The tunnel approach is made with the HTTP proxy CONNECT request and requires that the proxy allows direct connect to the remote port number curl wants to tunnel through to.
+<p class="level0"><a name="-P"></a><span class="nroffip">-P, --ftp-port &lt;address&gt;</span>
+<p class="level1">(FTP) Reverses the default initiator/listener roles when connecting with FTP. This switch makes curl use active mode. In practice, curl then tells the server to connect back to the client's specified address and port, while passive mode asks the server to setup an IP address and port for it to connect to. &lt;address&gt; should be one of:
+<p class="level2">
+<p class="level1"><a name="interface"></a><span class="nroffip">interface</span>
+<p class="level2">i.e "eth0" to specify which interface's IP address you want to use (Unix only)
+<p class="level1"><a name="IP"></a><span class="nroffip">IP address</span>
+<p class="level2">i.e "192.168.10.1" to specify the exact IP address
+<p class="level1"><a name="host"></a><span class="nroffip">host name</span>
+<p class="level2">i.e "my.host.domain" to specify the machine
+<p class="level1"><a name="-"></a><span class="nroffip">-</span>
+<p class="level2">make curl pick the same IP address that is already used for the control connection
+<p class="level1">
+<p class="level1">If this option is used several times, the last one will be used. Disable the use of PORT with <a class="emphasis" href="#--ftp-pasv">--ftp-pasv</a>. Disable the attempt to use the EPRT command instead of PORT by using <a class="emphasis" href="#--disable-eprt">--disable-eprt</a>. EPRT is really PORT++.
+<p class="level1">Starting in 7.19.5, you can append ":[start]-[end]" to the right of the address, to tell curl what TCP port range to use. That means you specify a port range, from a lower to a higher number. A single number works as well, but do note that it increases the risk of failure since the port may not be available.
+<p class="level0"><a name="--pass"></a><span class="nroffip">--pass &lt;phrase&gt;</span>
+<p class="level1">(SSL/SSH) Passphrase for the private key
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--post301"></a><span class="nroffip">--post301</span>
+<p class="level1">(HTTP) Tells curl to respect <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>/10.3.2 and not convert POST requests into GET requests when following a 301 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 <a class="emphasis" href="#-L">-L, --location</a> (Added in 7.17.1)
+<p class="level0"><a name="--post302"></a><span class="nroffip">--post302</span>
+<p class="level1">(HTTP) Tells curl to respect <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>/10.3.2 and not convert POST requests into GET requests when following a 302 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 <a class="emphasis" href="#-L">-L, --location</a> (Added in 7.19.1)
+<p class="level0"><a name="--post303"></a><span class="nroffip">--post303</span>
+<p class="level1">(HTTP) Tells curl to respect <a href="http://www.ietf.org/rfc/rfc2616.txt">RFC 2616</a>/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 <a class="emphasis" href="#-L">-L, --location</a> (Added in 7.26.0)
+<p class="level0"><a name="--proto"></a><span class="nroffip">--proto &lt;protocols&gt;</span>
+<p class="level1">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 name or 'all', optionally prefixed by zero or more modifiers. Available modifiers are:
+<p class="level2">
+<p class="level2"><a class="bold" href="#">+</a> Permit this protocol in addition to protocols already permitted (this is the default if no modifier is used).
+<p class="level2"><a class="bold" href="#-">-</a> Deny this protocol, removing it from the list of protocols already permitted.
+<p class="level2"><a class="bold" href="#">=</a> Permit only this protocol (ignoring the list already permitted), though subject to later modification by subsequent entries in the comma separated list.
+<p class="level1">
+<p class="level0"><a name=""></a><span class="nroffip"></span>
+<p class="level1">For example:
+<p class="level2">
+<p class="level2"><a class="bold" href="#--proto">--proto -ftps</a> uses the default protocols, but disables ftps
+<p class="level2"><a class="bold" href="#--proto">--proto -all,https,+http</a> only enables http and https
+<p class="level2"><a class="bold" href="#--proto">--proto =http,https</a> also only enables http and https
+<p class="level1">
+<p class="level0"><a name=""></a><span class="nroffip"></span>
+<p class="level1">Unknown protocols produce a warning. This allows scripts to safely rely on being able to disable potentially dangerous protocols, without relying upon support for that protocol being built into curl to avoid an error.
+<p class="level1">This option can be used multiple times, in which case the effect is the same as concatenating the protocols into one instance of the option.
+<p class="level1">(Added in 7.20.2)
+<p class="level0"><a name="--proto-redir"></a><span class="nroffip">--proto-redir &lt;protocols&gt;</span>
+<p class="level1">Tells curl to use the listed protocols after a redirect. See --proto for how protocols are represented.
+<p class="level1">(Added in 7.20.2)
+<p class="level0"><a name="--proxy-anyauth"></a><span class="nroffip">--proxy-anyauth</span>
+<p class="level1">Tells curl to pick a suitable authentication method when communicating with the given proxy. This might cause an extra request/response round-trip. (Added in 7.13.2)
+<p class="level0"><a name="--proxy-basic"></a><span class="nroffip">--proxy-basic</span>
+<p class="level1">Tells curl to use HTTP Basic authentication when communicating with the given proxy. Use <a class="emphasis" href="#--basic">--basic</a> for enabling HTTP Basic with a remote host. Basic is the default authentication method curl uses with proxies.
+<p class="level0"><a name="--proxy-digest"></a><span class="nroffip">--proxy-digest</span>
+<p class="level1">Tells curl to use HTTP Digest authentication when communicating with the given proxy. Use <a class="emphasis" href="#--digest">--digest</a> for enabling HTTP Digest with a remote host.
+<p class="level0"><a name="--proxy-negotiate"></a><span class="nroffip">--proxy-negotiate</span>
+<p class="level1">Tells curl to use HTTP Negotiate authentication when communicating with the given proxy. Use <a class="emphasis" href="#--negotiate">--negotiate</a> for enabling HTTP Negotiate with a remote host. (Added in 7.17.1)
+<p class="level0"><a name="--proxy-ntlm"></a><span class="nroffip">--proxy-ntlm</span>
+<p class="level1">Tells curl to use HTTP NTLM authentication when communicating with the given proxy. Use <a class="emphasis" href="#--ntlm">--ntlm</a> for enabling NTLM with a remote host.
+<p class="level0"><a name="--proxy10"></a><span class="nroffip">--proxy1.0 &lt;proxyhost[:port]&gt;</span>
+<p class="level1">Use the specified HTTP 1.0 proxy. If the port number is not specified, it is assumed at port 1080.
+<p class="level1">The only difference between this and the HTTP proxy option (<a class="emphasis" href="#-x">-x, --proxy</a>), is that attempts to use CONNECT through the proxy will specify an HTTP 1.0 protocol instead of the default HTTP 1.1.
+<p class="level0"><a name="--pubkey"></a><span class="nroffip">--pubkey &lt;key&gt;</span>
+<p class="level1">(SSH) Public key file name. Allows you to provide your public key in this separate file.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-q"></a><span class="nroffip">-q</span>
+<p class="level1">If used as the first parameter on the command line, the <span Class="emphasis">curlrc</span> config file will not be read and used. See the <a class="emphasis" href="#-K">-K, --config</a> for details on the default config file search path.
+<p class="level0"><a name="-Q"></a><span class="nroffip">-Q, --quote &lt;command&gt;</span>
+<p class="level1">(FTP/SFTP) Send an arbitrary command to the remote FTP or SFTP server. Quote commands are sent BEFORE the transfer takes place (just after the initial PWD command in an FTP transfer, to be exact). To make commands take place after a successful transfer, prefix them with a dash '-'. To make commands be sent after curl has changed the working directory, just before the transfer command(s), prefix the command with a '+' (this is only supported for FTP). You may specify any number of commands. If the server returns failure for one of the commands, the entire operation will be aborted. You must send syntactically correct FTP commands as <a href="http://www.ietf.org/rfc/rfc959.txt">RFC 959</a> defines to FTP servers, or one of the commands listed below to SFTP servers. This option can be used multiple times. When speaking to an FTP server, prefix the command with an asterisk (*) to make curl continue even if the command fails as by default curl will stop at first failure.
+<p class="level1">SFTP is a binary protocol. Unlike for FTP, curl interprets SFTP quote commands itself before sending them to the server. File names may be quoted shell-style to embed spaces or special characters. Following is the list of all supported SFTP quote commands:
+<p class="level2">
+<p class="level1"><a name="chgrp"></a><span class="nroffip">chgrp group file</span>
+<p class="level2">The chgrp command sets the group ID of the file named by the file operand to the group ID specified by the group operand. The group operand is a decimal integer group ID.
+<p class="level1"><a name="chmod"></a><span class="nroffip">chmod mode file</span>
+<p class="level2">The chmod command modifies the file mode bits of the specified file. The mode operand is an octal integer mode number.
+<p class="level1"><a name="chown"></a><span class="nroffip">chown user file</span>
+<p class="level2">The chown command sets the owner of the file named by the file operand to the user ID specified by the user operand. The user operand is a decimal integer user ID.
+<p class="level1"><a name="ln"></a><span class="nroffip">ln source_file target_file</span>
+<p class="level2">The ln and symlink commands create a symbolic link at the target_file location pointing to the source_file location.
+<p class="level1"><a name="mkdir"></a><span class="nroffip">mkdir directory_name</span>
+<p class="level2">The mkdir command creates the directory named by the directory_name operand.
+<p class="level1"><a name="pwd"></a><span class="nroffip">pwd</span>
+<p class="level2">The pwd command returns the absolute pathname of the current working directory.
+<p class="level1"><a name="rename"></a><span class="nroffip">rename source target</span>
+<p class="level2">The rename command renames the file or directory named by the source operand to the destination path named by the target operand.
+<p class="level1"><a name="rm"></a><span class="nroffip">rm file</span>
+<p class="level2">The rm command removes the file specified by the file operand.
+<p class="level1"><a name="rmdir"></a><span class="nroffip">rmdir directory</span>
+<p class="level2">The rmdir command removes the directory entry specified by the directory operand, provided it is empty.
+<p class="level1"><a name="symlink"></a><span class="nroffip">symlink source_file target_file</span>
+<p class="level2">See ln.
+<p class="level1">
+<p class="level0"><a name="-r"></a><span class="nroffip">-r, --range &lt;range&gt;</span>
+<p class="level1">(HTTP/FTP/SFTP/FILE) Retrieve a byte range (i.e a partial document) from a HTTP/1.1, FTP or SFTP server or a local FILE. Ranges can be specified in a number of ways.
+<p class="level2">
+<p class="level2"><span Class="bold">0-499</span> specifies the first 500 bytes
+<p class="level2"><span Class="bold">500-999</span> specifies the second 500 bytes
+<p class="level2"><span Class="bold">-500</span> specifies the last 500 bytes
+<p class="level2"><span Class="bold">9500-</span> specifies the bytes from offset 9500 and forward
+<p class="level2"><span Class="bold">0-0,-1</span> specifies the first and last byte only(*)(H)
+<p class="level2"><span Class="bold">500-700,600-799</span> specifies 300 bytes from offset 500(H)
+<p class="level2"><span Class="bold">100-199,500-599</span> specifies two separate 100-byte ranges(*)(H)
+<p class="level1">
+<p class="level1">(*) = NOTE that this will cause the server to reply with a multipart response!
+<p class="level1">Only digit characters (0-9) are valid in the 'start' and 'stop' fields of the 'start-stop' range syntax. If a non-digit character is given in the range, the server's response will be unspecified, depending on the server's configuration.
+<p class="level1">You should also be aware that many HTTP/1.1 servers do not have this feature enabled, so that when you attempt to get a range, you'll instead get the whole document.
+<p class="level1">FTP and SFTP range downloads only support the simple 'start-stop' syntax (optionally with one of the numbers omitted). FTP use depends on the extended FTP command SIZE.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-R"></a><span class="nroffip">-R, --remote-time</span>
+<p class="level1">When used, this will make curl attempt to figure out the timestamp of the remote file, and if that is available make the local file get that same timestamp.
+<p class="level0"><a name="--random-file"></a><span class="nroffip">--random-file &lt;file&gt;</span>
+<p class="level1">(SSL) Specify the path name to file containing what will be considered as random data. The data is used to seed the random engine for SSL connections. See also the <a class="emphasis" href="#--egd-file">--egd-file</a> option.
+<p class="level0"><a name="--raw"></a><span class="nroffip">--raw</span>
+<p class="level1">(HTTP) When used, it disables all internal HTTP decoding of content or transfer encodings and instead makes them passed on unaltered, raw. (Added in 7.16.2)
+<p class="level0"><a name="--remote-name-all"></a><span class="nroffip">--remote-name-all</span>
+<p class="level1">This option changes the default action for all given URLs to be dealt with as if <a class="emphasis" href="#-O">-O, --remote-name</a> were used for each one. So if you want to disable that for a specific URL after <a class="emphasis" href="#--remote-name-all">--remote-name-all</a> has been used, you must use "-o -" or <span Class="emphasis">--no-remote-name</span>. (Added in 7.19.0)
+<p class="level0"><a name="--resolve"></a><span class="nroffip">--resolve &lt;host:port:address&gt;</span>
+<p class="level1">Provide a custom address for a specific host and port pair. Using this, you can make the curl requests(s) use a specified address and prevent the otherwise normally resolved address to be used. Consider it a sort of /etc/hosts alternative provided on the command line. The port number should be the number used for the specific protocol the host will be used for. It means you need several entries if you want to provide address for the same host but different ports.
+<p class="level1">This option can be used many times to add many host names to resolve.
+<p class="level1">(Added in 7.21.3)
+<p class="level0"><a name="--retry"></a><span class="nroffip">--retry &lt;num&gt;</span>
+<p class="level1">If a transient error is returned when curl tries to perform a transfer, it will retry this number of times before giving up. Setting the number to 0 makes curl do no retries (which is the default). Transient error means either: a timeout, an FTP 4xx response code or an HTTP 5xx response code.
+<p class="level1">When curl is about to retry a transfer, it will first wait one second and then for all forthcoming retries it will double the waiting time until it reaches 10 minutes which then will be the delay between the rest of the retries. By using <a class="emphasis" href="#--retry-delay">--retry-delay</a> you disable this exponential backoff algorithm. See also <a class="emphasis" href="#--retry-max-time">--retry-max-time</a> to limit the total time allowed for retries. (Added in 7.12.3)
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--retry-delay"></a><span class="nroffip">--retry-delay &lt;seconds&gt;</span>
+<p class="level1">Make curl sleep this amount of time before each retry when a transfer has failed with a transient error (it changes the default backoff time algorithm between retries). This option is only interesting if <a class="emphasis" href="#--retry">--retry</a> is also used. Setting this delay to zero will make curl use the default backoff time. (Added in 7.12.3)
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--retry-max-time"></a><span class="nroffip">--retry-max-time &lt;seconds&gt;</span>
+<p class="level1">The retry timer is reset before the first transfer attempt. Retries will be done as usual (see <a class="emphasis" href="#--retry">--retry</a>) as long as the timer hasn't reached this given limit. Notice that if the timer hasn't reached the limit, the request will be made and while performing, it may take longer than this given time period. To limit a single request&acute;s maximum time, use <a class="emphasis" href="#-m">-m, --max-time</a>. Set this option to zero to not timeout retries. (Added in 7.12.3)
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-s"></a><span class="nroffip">-s, --silent</span>
+<p class="level1">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.
+<p class="level0"><a name="--sasl-ir"></a><span class="nroffip">--sasl-ir</span>
+<p class="level1">Enable initial response in SASL authentication. (Added in 7.31.0)
+<p class="level0"><a name="-S"></a><span class="nroffip">-S, --show-error</span>
+<p class="level1">When used with <a class="emphasis" href="#-s">-s</a> it makes curl show an error message if it fails.
+<p class="level0"><a name="--ssl"></a><span class="nroffip">--ssl</span>
+<p class="level1">(FTP, POP3, IMAP, SMTP) Try to use SSL/TLS for the connection. Reverts to a non-secure connection if the server doesn't support SSL/TLS. See also <a class="emphasis" href="#--ftp-ssl-control">--ftp-ssl-control</a> and <a class="emphasis" href="#--ssl-reqd">--ssl-reqd</a> for different levels of encryption required. (Added in 7.20.0)
+<p class="level1">This option was formerly known as <span Class="emphasis">--ftp-ssl</span> (Added in 7.11.0). That option name can still be used but will be removed in a future version.
+<p class="level0"><a name="--ssl-reqd"></a><span class="nroffip">--ssl-reqd</span>
+<p class="level1">(FTP, POP3, IMAP, SMTP) Require SSL/TLS for the connection. Terminates the connection if the server doesn't support SSL/TLS. (Added in 7.20.0)
+<p class="level1">This option was formerly known as <span Class="emphasis">--ftp-ssl-reqd</span> (added in 7.15.5). That option name can still be used but will be removed in a future version.
+<p class="level0"><a name="--ssl-allow-beast"></a><span class="nroffip">--ssl-allow-beast</span>
+<p class="level1">(SSL) This option tells curl to not work around a security flaw in the SSL3 and TLS1.0 protocols known as BEAST. If this option isn't used, the SSL layer may use work-arounds known to cause interoperability problems with some older SSL implementations. WARNING: this option loosens the SSL security, and by using this flag you ask for exactly that. (Added in 7.25.0)
+<p class="level0"><a name="--socks4"></a><span class="nroffip">--socks4 &lt;host[:port]&gt;</span>
+<p class="level1">Use the specified SOCKS4 proxy. If the port number is not specified, it is assumed at port 1080. (Added in 7.15.2)
+<p class="level1">This option overrides any previous use of <a class="emphasis" href="#-x">-x, --proxy</a>, as they are mutually exclusive.
+<p class="level1">Since 7.21.7, this option is superfluous since you can specify a socks4 proxy with <a class="emphasis" href="#-x">-x, --proxy</a> using a socks4:// protocol prefix.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--socks4a"></a><span class="nroffip">--socks4a &lt;host[:port]&gt;</span>
+<p class="level1">Use the specified SOCKS4a proxy. If the port number is not specified, it is assumed at port 1080. (Added in 7.18.0)
+<p class="level1">This option overrides any previous use of <a class="emphasis" href="#-x">-x, --proxy</a>, as they are mutually exclusive.
+<p class="level1">Since 7.21.7, this option is superfluous since you can specify a socks4a proxy with <a class="emphasis" href="#-x">-x, --proxy</a> using a socks4a:// protocol prefix.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--socks5-hostname"></a><span class="nroffip">--socks5-hostname &lt;host[:port]&gt;</span>
+<p class="level1">Use the specified SOCKS5 proxy (and let the proxy resolve the host name). If the port number is not specified, it is assumed at port 1080. (Added in 7.18.0)
+<p class="level1">This option overrides any previous use of <a class="emphasis" href="#-x">-x, --proxy</a>, as they are mutually exclusive.
+<p class="level1">Since 7.21.7, this option is superfluous since you can specify a socks5 hostname proxy with <a class="emphasis" href="#-x">-x, --proxy</a> using a socks5h:// protocol prefix.
+<p class="level1">If this option is used several times, the last one will be used. (This option was previously wrongly documented and used as --socks without the number appended.)
+<p class="level0"><a name="--socks5"></a><span class="nroffip">--socks5 &lt;host[:port]&gt;</span>
+<p class="level1">Use the specified SOCKS5 proxy - but resolve the host name locally. If the port number is not specified, it is assumed at port 1080.
+<p class="level1">This option overrides any previous use of <a class="emphasis" href="#-x">-x, --proxy</a>, as they are mutually exclusive.
+<p class="level1">Since 7.21.7, this option is superfluous since you can specify a socks5 proxy with <a class="emphasis" href="#-x">-x, --proxy</a> using a socks5:// protocol prefix.
+<p class="level1">If this option is used several times, the last one will be used. (This option was previously wrongly documented and used as --socks without the number appended.)
+<p class="level1">This option (as well as <a class="emphasis" href="#--socks4">--socks4</a>) does not work with IPV6, FTPS or LDAP.
+<p class="level0"><a name="--socks5-gssapi-service"></a><span class="nroffip">--socks5-gssapi-service &lt;servicename&gt;</span>
+<p class="level1">The default service name for a socks server is rcmd/server-fqdn. This option allows you to change it.
+<p class="level1">Examples: --socks5 proxy-name <a class="emphasis" href="#--socks5-gssapi-service">--socks5-gssapi-service</a> sockd would use sockd/proxy-name --socks5 proxy-name <a class="emphasis" href="#--socks5-gssapi-service">--socks5-gssapi-service</a> sockd/real-name would use sockd/real-name for cases where the proxy-name does not match the principal name. (Added in 7.19.4).
+<p class="level0"><a name="--socks5-gssapi-nec"></a><span class="nroffip">--socks5-gssapi-nec</span>
+<p class="level1">As part of the gssapi negotiation a protection mode is negotiated. <a href="http://www.ietf.org/rfc/rfc1961.txt">RFC 1961</a> says in section 4.3/4.4 it should be protected, but the NEC reference implementation does not. The option <a class="emphasis" href="#--socks5-gssapi-nec">--socks5-gssapi-nec</a> allows the unprotected exchange of the protection mode negotiation. (Added in 7.19.4).
+<p class="level0"><a name="--stderr"></a><span class="nroffip">--stderr &lt;file&gt;</span>
+<p class="level1">Redirect all writes to stderr to the specified file instead. If the file name is a plain '-', it is instead written to stdout.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-t"></a><span class="nroffip">-t, --telnet-option &lt;OPT=val&gt;</span>
+<p class="level1">Pass options to the telnet protocol. Supported options are:
+<p class="level1">TTYPE=&lt;term&gt; Sets the terminal type.
+<p class="level1">XDISPLOC=&lt;X display&gt; Sets the X display location.
+<p class="level1">NEW_ENV=&lt;var,val&gt; Sets an environment variable.
+<p class="level0"><a name="-T"></a><span class="nroffip">-T, --upload-file &lt;file&gt;</span>
+<p class="level1">This transfers the specified local file to the remote URL. If there is no file part in the specified URL, Curl will append the local file name. NOTE that you must use a trailing / on the last directory to really prove to Curl that there is no file name or curl will think that your last directory name is the remote file name to use. That will most likely cause the upload operation to fail. If this is used on an HTTP(S) server, the PUT command will be used.
+<p class="level1">Use the file name "-" (a single dash) to use stdin instead of a given file. Alternately, the file name "." (a single period) may be specified instead of "-" to use stdin in non-blocking mode to allow reading server output while stdin is being uploaded.
+<p class="level1">You can specify one -T for each URL on the command line. Each -T + URL pair specifies what to upload and to where. curl also supports "globbing" of the -T argument, meaning that you can upload multiple files to a single URL by using the same URL globbing style supported in the URL, like this:
+<p class="level1">curl -T "{file1,file2}" <a href="http://www.uploadtothissite.com">http://www.uploadtothissite.com</a>
+<p class="level1">or even
+<p class="level1">curl -T "img[1-1000].png" <a href="ftp://ftp.picturemania.com/upload/">ftp://ftp.picturemania.com/upload/</a>
+<p class="level0"><a name="--tcp-nodelay"></a><span class="nroffip">--tcp-nodelay</span>
+<p class="level1">Turn on the TCP_NODELAY option. See the <span Class="emphasis">curl_easy_setopt(3)</span> man page for details about this option. (Added in 7.11.2)
+<p class="level0"><a name="--tftp-blksize"></a><span class="nroffip">--tftp-blksize &lt;value&gt;</span>
+<p class="level1">(TFTP) Set TFTP BLKSIZE option (must be &gt;512). This is the block size that curl will try to use when transferring data to or from a TFTP server. By default 512 bytes will be used.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level1">(Added in 7.20.0)
+<p class="level0"><a name="--tlsauthtype"></a><span class="nroffip">--tlsauthtype &lt;authtype&gt;</span>
+<p class="level1">Set TLS authentication type. Currently, the only supported option is "SRP", for TLS-SRP (<a href="http://www.ietf.org/rfc/rfc5054.txt">RFC 5054</a>). If <a class="emphasis" href="#--tlsuser">--tlsuser</a> and <a class="emphasis" href="#--tlspassword">--tlspassword</a> are specified but <a class="emphasis" href="#--tlsauthtype">--tlsauthtype</a> is not, then this option defaults to "SRP". (Added in 7.21.4)
+<p class="level0"><a name="--tlsuser"></a><span class="nroffip">--tlsuser &lt;user&gt;</span>
+<p class="level1">Set username for use with the TLS authentication method specified with <a class="emphasis" href="#--tlsauthtype">--tlsauthtype</a>. Requires that <a class="emphasis" href="#--tlspassword">--tlspassword</a> also be set. (Added in 7.21.4)
+<p class="level0"><a name="--tlspassword"></a><span class="nroffip">--tlspassword &lt;password&gt;</span>
+<p class="level1">Set password for use with the TLS authentication method specified with <a class="emphasis" href="#--tlsauthtype">--tlsauthtype</a>. Requires that <a class="emphasis" href="#--tlsuser">--tlsuser</a> also be set. (Added in 7.21.4)
+<p class="level0"><a name="--tr-encoding"></a><span class="nroffip">--tr-encoding</span>
+<p class="level1">(HTTP) Request a compressed Transfer-Encoding response using one of the algorithms curl supports, and uncompress the data while receiving it.
+<p class="level1">(Added in 7.21.6)
+<p class="level0"><a name="--trace"></a><span class="nroffip">--trace &lt;file&gt;</span>
+<p class="level1">Enables a full trace dump of all incoming and outgoing data, including descriptive information, to the given output file. Use "-" as filename to have the output sent to stdout.
+<p class="level1">This option overrides previous uses of <a class="emphasis" href="#-v">-v, --verbose</a> or <a class="emphasis" href="#--trace-ascii">--trace-ascii</a>.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--trace-ascii"></a><span class="nroffip">--trace-ascii &lt;file&gt;</span>
+<p class="level1">Enables a full trace dump of all incoming and outgoing data, including descriptive information, to the given output file. Use "-" as filename to have the output sent to stdout.
+<p class="level1">This is very similar to <a class="emphasis" href="#--trace">--trace</a>, but leaves out the hex part and only shows the ASCII part of the dump. It makes smaller output that might be easier to read for untrained humans.
+<p class="level1">This option overrides previous uses of <a class="emphasis" href="#-v">-v, --verbose</a> or <a class="emphasis" href="#--trace">--trace</a>.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--trace-time"></a><span class="nroffip">--trace-time</span>
+<p class="level1">Prepends a time stamp to each trace or verbose line that curl displays. (Added in 7.14.0)
+<p class="level0"><a name="-u"></a><span class="nroffip">-u, --user &lt;user:password;options&gt;</span>
+<p class="level1">Specify the user name, password and optional login options to use for server authentication. Overrides <a class="emphasis" href="#-n">-n, --netrc</a> and <a class="emphasis" href="#--netrc-optional">--netrc-optional</a>.
+<p class="level1">If you simply specify the user name, with or without the login options, curl will prompt for a password.
+<p class="level1">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".
+<p class="level1">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 <a href="http://www.ietf.org/rfc/rfc2384.txt">RFC 2384</a>, RFC 5092 and IETF draft draft-earhart-url-smtp-00.txt (Added in 7.31.0).
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-U"></a><span class="nroffip">-U, --proxy-user &lt;user:password&gt;</span>
+<p class="level1">Specify the user name and password to use for proxy authentication.
+<p class="level1">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 :".
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="--url"></a><span class="nroffip">--url &lt;URL&gt;</span>
+<p class="level1">Specify a URL to fetch. This option is mostly handy when you want to specify URL(s) in a config file.
+<p class="level1">This option may be used any number of times. To control where this URL is written, use the <a class="emphasis" href="#-o">-o, --output</a> or the <a class="emphasis" href="#-O">-O, --remote-name</a> options.
+<p class="level0"><a name="-v"></a><span class="nroffip">-v, --verbose</span>
+<p class="level1">Makes the fetching more verbose/talkative. Mostly useful for debugging. A line starting with '&gt;' means "header data" sent by curl, '&lt;' means "header data" received by curl that is hidden in normal cases, and a line starting with '*' means additional info provided by curl.
+<p class="level1">Note that if you only want HTTP headers in the output, <a class="emphasis" href="#-i">-i, --include</a> might be the option you're looking for.
+<p class="level1">If you think this option still doesn't give you enough details, consider using <a class="emphasis" href="#--trace">--trace</a> or <a class="emphasis" href="#--trace-ascii">--trace-ascii</a> instead.
+<p class="level1">This option overrides previous uses of <a class="emphasis" href="#--trace-ascii">--trace-ascii</a> or <a class="emphasis" href="#--trace">--trace</a>.
+<p class="level1">Use <a class="emphasis" href="#-s">-s, --silent</a> to make curl quiet.
+<p class="level0"><a name="-w"></a><span class="nroffip">-w, --write-out &lt;format&gt;</span>
+<p class="level1">Defines what to display on stdout after a completed and successful operation. The format is a string that may contain plain text mixed with any number of variables. The string can be specified as "string", to get read from a particular file you specify it "@filename" and to tell curl to read the format from stdin you write "@-".
+<p class="level1">The variables present in the output format will be substituted by the value or text that curl thinks fit, as described below. All variables are specified as %{variable_name} and to output a normal % you just write them as %%. You can output a newline by using \n, a carriage return with \r and a tab space with \t.
+<p class="level1"><span Class="bold">NOTE:</span> The %-symbol is a special symbol in the win32-environment, where all occurrences of % must be doubled when using this option.
+<p class="level1">The variables available are:
+<p class="level2">
+<p class="level2"><span Class="bold">content_type</span> The Content-Type of the requested document, if there was any.
+<p class="level2"><span Class="bold">filename_effective</span> The ultimate filename that curl writes out to. This is only meaningful if curl is told to write to a file with the <span Class="emphasis">--remote-name</span> or <span Class="emphasis">--output</span> option. It's most useful in combination with the <span Class="emphasis">--remote-header-name</span> option. (Added in 7.25.1)
+<p class="level2"><span Class="bold">ftp_entry_path</span> The initial path curl ended up in when logging on to the remote FTP server. (Added in 7.15.4)
+<p class="level2"><span Class="bold">http_code</span> The numerical response code that was found in the last retrieved HTTP(S) or FTP(s) transfer. In 7.18.2 the alias <span Class="bold">response_code</span> was added to show the same info.
+<p class="level2"><span Class="bold">http_connect</span> The numerical code that was found in the last response (from a proxy) to a curl CONNECT request. (Added in 7.12.4)
+<p class="level2"><span Class="bold">local_ip</span> The IP address of the local end of the most recently done connection - can be either IPv4 or IPv6 (Added in 7.29.0)
+<p class="level2"><span Class="bold">local_port</span> The local port number of the most recently done connection (Added in 7.29.0)
+<p class="level2"><span Class="bold">num_connects</span> Number of new connects made in the recent transfer. (Added in 7.12.3)
+<p class="level2"><span Class="bold">num_redirects</span> Number of redirects that were followed in the request. (Added in 7.12.3)
+<p class="level2"><span Class="bold">redirect_url</span> When an HTTP request was made without -L to follow redirects, this variable will show the actual URL a redirect <span Class="emphasis">would</span> take you to. (Added in 7.18.2)
+<p class="level2"><span Class="bold">remote_ip</span> The remote IP address of the most recently done connection - can be either IPv4 or IPv6 (Added in 7.29.0)
+<p class="level2"><span Class="bold">remote_port</span> The remote port number of the most recently done connection (Added in 7.29.0)
+<p class="level2"><span Class="bold">size_download</span> The total amount of bytes that were downloaded.
+<p class="level2"><span Class="bold">size_header</span> The total amount of bytes of the downloaded headers.
+<p class="level2"><span Class="bold">size_request</span> The total amount of bytes that were sent in the HTTP request.
+<p class="level2"><span Class="bold">size_upload</span> The total amount of bytes that were uploaded.
+<p class="level2"><span Class="bold">speed_download</span> The average download speed that curl measured for the complete download. Bytes per second.
+<p class="level2"><span Class="bold">speed_upload</span> The average upload speed that curl measured for the complete upload. Bytes per second.
+<p class="level2"><span Class="bold">ssl_verify_result</span> The result of the SSL peer certificate verification that was requested. 0 means the verification was successful. (Added in 7.19.0)
+<p class="level2"><span Class="bold">time_appconnect</span> The time, in seconds, it took from the start until the SSL/SSH/etc connect/handshake to the remote host was completed. (Added in 7.19.0)
+<p class="level2"><span Class="bold">time_connect</span> The time, in seconds, it took from the start until the TCP connect to the remote host (or proxy) was completed.
+<p class="level2"><span Class="bold">time_namelookup</span> The time, in seconds, it took from the start until the name resolving was completed.
+<p class="level2"><span Class="bold">time_pretransfer</span> The time, in seconds, it took from the start until the file transfer was just about to begin. This includes all pre-transfer commands and negotiations that are specific to the particular protocol(s) involved.
+<p class="level2"><span Class="bold">time_redirect</span> The time, in seconds, it took for all redirection steps include name lookup, connect, pretransfer and transfer before the final transaction was started. time_redirect shows the complete execution time for multiple redirections. (Added in 7.12.3)
+<p class="level2"><span Class="bold">time_starttransfer</span> The time, in seconds, it took from the start until the first byte was just about to be transferred. This includes time_pretransfer and also the time the server needed to calculate the result.
+<p class="level2"><span Class="bold">time_total</span> The total time, in seconds, that the full operation lasted. The time will be displayed with millisecond resolution.
+<p class="level2"><span Class="bold">url_effective</span> The URL that was fetched last. This is most meaningful if you've told curl to follow location: headers.
+<p class="level1">
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-x"></a><span class="nroffip">-x, --proxy &lt;[protocol://][user:password@]proxyhost[:port]&gt;</span>
+<p class="level1">Use the specified proxy.
+<p class="level1">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)
+<p class="level1">If the port number is not specified in the proxy string, it is assumed to be 1080.
+<p class="level1">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 "" to override it.
+<p class="level1">All operations that are performed over an HTTP proxy will transparently be converted to HTTP. It means that certain protocol specific operations might not be available. This is not the case if you can tunnel through the proxy, as one with the <a class="emphasis" href="#-p">-p, --proxytunnel</a> option.
+<p class="level1">User and password that might be provided in the proxy string are URL decoded by curl. This allows you to pass in special characters such as @ by using %40 or pass in a colon with %3a.
+<p class="level1">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.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-X"></a><span class="nroffip">-X, --request &lt;command&gt;</span>
+<p class="level1">(HTTP) Specifies a custom request method to use when communicating with the HTTP server. The specified request will be used instead of the method otherwise used (which defaults to GET). Read the HTTP 1.1 specification for details and explanations. Common additional HTTP requests include PUT and DELETE, but related technologies like WebDAV offers PROPFIND, COPY, MOVE and more.
+<p class="level1">Normally you don't need this option. All sorts of GET, HEAD, POST and PUT requests are rather invoked by using dedicated command line options.
+<p class="level1">This option only changes the actual word used in the HTTP request, it does not alter the way curl behaves. So for example if you want to make a proper HEAD request, using -X HEAD will not suffice. You need to use the <a class="emphasis" href="#-I">-I, --head</a> option.
+<p class="level1">(FTP) Specifies a custom FTP command to use instead of LIST when doing file lists with FTP.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level1">
+<p class="level0"><a name="--xattr"></a><span class="nroffip">--xattr</span>
+<p class="level1">When saving output to a file, this option tells curl to store certain file 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.
+<p class="level1">
+<p class="level0"><a name="-y"></a><span class="nroffip">-y, --speed-time &lt;time&gt;</span>
+<p class="level1">If a download is slower than speed-limit bytes per second during a speed-time period, the download gets aborted. If speed-time is used, the default speed-limit will be 1 unless set with <a class="emphasis" href="#-Y">-Y</a>.
+<p class="level1">This option controls transfers and thus will not affect slow connects etc. If this is a concern for you, try the <a class="emphasis" href="#--connect-timeout">--connect-timeout</a> option.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-Y"></a><span class="nroffip">-Y, --speed-limit &lt;speed&gt;</span>
+<p class="level1">If a download is slower than this given speed (in bytes per second) for speed-time seconds it gets aborted. speed-time is set with <a class="emphasis" href="#-y">-y</a> and is 30 if not set.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-z"></a><span class="nroffip">-z, --time-cond &lt;date expression&gt;|&lt;file&gt;</span>
+<p class="level1">(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 &lt;date expression&gt; can be all sorts of date strings or if it doesn't match any internal ones, it is taken as a filename and tries to get the modification date (mtime) from &lt;file&gt; instead. See the <span Class="emphasis">curl_getdate(3)</span> man pages for date expression details.
+<p class="level1">Start the date expression with a dash (-) to make it request for a document that is older than the given date/time, default is a document that is newer than the specified date/time.
+<p class="level1">If this option is used several times, the last one will be used.
+<p class="level0"><a name="-h"></a><span class="nroffip">-h, --help</span>
+<p class="level1">Usage help.
+<p class="level0"><a name="-M"></a><span class="nroffip">-M, --manual</span>
+<p class="level1">Manual. Display the huge help text.
+<p class="level0"><a name="-V"></a><span class="nroffip">-V, --version</span>
+<p class="level1">Displays information about curl and the libcurl version it uses.
+<p class="level1">The first line includes the full version of curl, libcurl and other 3rd party libraries linked with the executable.
+<p class="level1">The second line (starts with "Protocols:") shows all protocols that libcurl reports to support.
+<p class="level1">The third line (starts with "Features:") shows specific features libcurl reports to offer. Available features include:
+<p class="level2">
+<p class="level1"><a name="IPv6"></a><span class="nroffip">IPv6</span>
+<p class="level2">You can use IPv6 with this.
+<p class="level1"><a name="krb4"></a><span class="nroffip">krb4</span>
+<p class="level2">Krb4 for FTP is supported.
+<p class="level1"><a name="SSL"></a><span class="nroffip">SSL</span>
+<p class="level2">HTTPS and FTPS are supported.
+<p class="level1"><a name="libz"></a><span class="nroffip">libz</span>
+<p class="level2">Automatic decompression of compressed files over HTTP is supported.
+<p class="level1"><a name="NTLM"></a><span class="nroffip">NTLM</span>
+<p class="level2">NTLM authentication is supported.
+<p class="level1"><a name="GSS-Negotiate"></a><span class="nroffip">GSS-Negotiate</span>
+<p class="level2">Negotiate authentication and krb5 for FTP is supported.
+<p class="level1"><a name="Debug"></a><span class="nroffip">Debug</span>
+<p class="level2">This curl uses a libcurl built with Debug. This enables more error-tracking and memory debugging etc. For curl-developers only!
+<p class="level1"><a name="AsynchDNS"></a><span class="nroffip">AsynchDNS</span>
+<p class="level2">This curl uses asynchronous name resolves.
+<p class="level1"><a name="SPNEGO"></a><span class="nroffip">SPNEGO</span>
+<p class="level2">SPNEGO Negotiate authentication is supported.
+<p class="level1"><a name="Largefile"></a><span class="nroffip">Largefile</span>
+<p class="level2">This curl supports transfers of large files, files larger than 2GB.
+<p class="level1"><a name="IDN"></a><span class="nroffip">IDN</span>
+<p class="level2">This curl supports IDN - international domain names.
+<p class="level1"><a name="SSPI"></a><span class="nroffip">SSPI</span>
+<p class="level2">SSPI is supported. If you use NTLM and set a blank user name, curl will authenticate with your current user and password.
+<p class="level1"><a name="TLS-SRP"></a><span class="nroffip">TLS-SRP</span>
+<p class="level2">SRP (Secure Remote Password) authentication is supported for TLS.
+<p class="level1"><a name="Metalink"></a><span class="nroffip">Metalink</span>
+<p class="level2">This curl supports Metalink (both version 3 and 4 (<a href="http://www.ietf.org/rfc/rfc5854.txt">RFC 5854</a>)), which describes mirrors and hashes. curl will use mirrors for failover if there are errors (such as the file or server not being available).
+<p class="level1"><a name="FILES"></a><h2 class="nroffsh">FILES</h2>
+<p class="level0"><span Class="emphasis">~/.curlrc</span>
+<p class="level1">Default config file, see <a class="emphasis" href="#-K">-K, --config</a> for details. <a name="ENVIRONMENT"></a><h2 class="nroffsh">ENVIRONMENT</h2>
+<p class="level0">The environment variables can be specified in lower case or upper case. The lower case version has precedence. http_proxy is an exception as it is only available in lower case.
+<p class="level0">Using an environment variable to set the proxy has the same effect as using the <span Class="emphasis">--proxy</span> option.
+<p class="level0">
+<p class="level0"><a name="httpproxy"></a><span class="nroffip">http_proxy [protocol://]&lt;host&gt;[:port]</span>
+<p class="level1">Sets the proxy server to use for HTTP.
+<p class="level0"><a name="HTTPSPROXY"></a><span class="nroffip">HTTPS_PROXY [protocol://]&lt;host&gt;[:port]</span>
+<p class="level1">Sets the proxy server to use for HTTPS.
+<p class="level0"><a name="url-protocolPROXY"></a><span class="nroffip">[url-protocol]_PROXY [protocol://]&lt;host&gt;[:port]</span>
+<p class="level1">Sets the proxy server to use for [url-protocol], where the protocol is a protocol that curl supports and as specified in a URL. FTP, FTPS, POP3, IMAP, SMTP, LDAP etc.
+<p class="level0"><a name="ALLPROXY"></a><span class="nroffip">ALL_PROXY [protocol://]&lt;host&gt;[:port]</span>
+<p class="level1">Sets the proxy server to use if no protocol-specific proxy is set.
+<p class="level0"><a name="NOPROXY"></a><span class="nroffip">NO_PROXY &lt;comma-separated list of hosts&gt;</span>
+<p class="level1">list of host names that shouldn't go through any proxy. If set to a asterisk '*' only, it matches all hosts. <a name="PROXY"></a><h2 class="nroffsh">PROXY PROTOCOL PREFIXES</h2>
+<p class="level0">Since curl version 7.21.7, the proxy string may be specified with a protocol:// prefix to specify alternative proxy protocols.
+<p class="level0">If no protocol is specified in the proxy string or if the string doesn't match a supported one, the proxy will be treated as an HTTP proxy.
+<p class="level0">The supported proxy protocol prefixes are as follows:
+<p class="level0"><a name="socks4"></a><span class="nroffip">socks4://</span>
+<p class="level1">Makes it the equivalent of <a class="emphasis" href="#--socks4">--socks4</a>
+<p class="level0"><a name="socks4a"></a><span class="nroffip">socks4a://</span>
+<p class="level1">Makes it the equivalent of <a class="emphasis" href="#--socks4a">--socks4a</a>
+<p class="level0"><a name="socks5"></a><span class="nroffip">socks5://</span>
+<p class="level1">Makes it the equivalent of <a class="emphasis" href="#--socks5">--socks5</a>
+<p class="level0"><a name="socks5h"></a><span class="nroffip">socks5h://</span>
+<p class="level1">Makes it the equivalent of <a class="emphasis" href="#--socks5-hostname">--socks5-hostname</a> <a name="EXIT"></a><h2 class="nroffsh">EXIT CODES</h2>
+<p class="level0">There are a bunch of different error codes and their corresponding error messages that may appear during bad conditions. At the time of this writing, the exit codes are:
+<p class="level0"><a name="1"></a><span class="nroffip">1</span>
+<p class="level1">Unsupported protocol. This build of curl has no support for this protocol.
+<p class="level0"><a name="2"></a><span class="nroffip">2</span>
+<p class="level1">Failed to initialize.
+<p class="level0"><a name="3"></a><span class="nroffip">3</span>
+<p class="level1">URL malformed. The syntax was not correct.
+<p class="level0"><a name="4"></a><span class="nroffip">4</span>
+<p class="level1">A feature or option that was needed to perform the desired request was not enabled or was explicitly disabled at build-time. To make curl able to do this, you probably need another build of libcurl!
+<p class="level0"><a name="5"></a><span class="nroffip">5</span>
+<p class="level1">Couldn't resolve proxy. The given proxy host could not be resolved.
+<p class="level0"><a name="6"></a><span class="nroffip">6</span>
+<p class="level1">Couldn't resolve host. The given remote host was not resolved.
+<p class="level0"><a name="7"></a><span class="nroffip">7</span>
+<p class="level1">Failed to connect to host.
+<p class="level0"><a name="8"></a><span class="nroffip">8</span>
+<p class="level1">FTP weird server reply. The server sent data curl couldn't parse.
+<p class="level0"><a name="9"></a><span class="nroffip">9</span>
+<p class="level1">FTP access denied. The server denied login or denied access to the particular resource or directory you wanted to reach. Most often you tried to change to a directory that doesn't exist on the server.
+<p class="level0"><a name="11"></a><span class="nroffip">11</span>
+<p class="level1">FTP weird PASS reply. Curl couldn't parse the reply sent to the PASS request.
+<p class="level0"><a name="13"></a><span class="nroffip">13</span>
+<p class="level1">FTP weird PASV reply, Curl couldn't parse the reply sent to the PASV request.
+<p class="level0"><a name="14"></a><span class="nroffip">14</span>
+<p class="level1">FTP weird 227 format. Curl couldn't parse the 227-line the server sent.
+<p class="level0"><a name="15"></a><span class="nroffip">15</span>
+<p class="level1">FTP can't get host. Couldn't resolve the host IP we got in the 227-line.
+<p class="level0"><a name="17"></a><span class="nroffip">17</span>
+<p class="level1">FTP couldn't set binary. Couldn't change transfer method to binary.
+<p class="level0"><a name="18"></a><span class="nroffip">18</span>
+<p class="level1">Partial file. Only a part of the file was transferred.
+<p class="level0"><a name="19"></a><span class="nroffip">19</span>
+<p class="level1">FTP couldn't download/access the given file, the RETR (or similar) command failed.
+<p class="level0"><a name="21"></a><span class="nroffip">21</span>
+<p class="level1">FTP quote error. A quote command returned error from the server.
+<p class="level0"><a name="22"></a><span class="nroffip">22</span>
+<p class="level1">HTTP page not retrieved. The requested url was not found or returned another error with the HTTP error code being 400 or above. This return code only appears if <a class="emphasis" href="#-f">-f, --fail</a> is used.
+<p class="level0"><a name="23"></a><span class="nroffip">23</span>
+<p class="level1">Write error. Curl couldn't write data to a local filesystem or similar.
+<p class="level0"><a name="25"></a><span class="nroffip">25</span>
+<p class="level1">FTP couldn't STOR file. The server denied the STOR operation, used for FTP uploading.
+<p class="level0"><a name="26"></a><span class="nroffip">26</span>
+<p class="level1">Read error. Various reading problems.
+<p class="level0"><a name="27"></a><span class="nroffip">27</span>
+<p class="level1">Out of memory. A memory allocation request failed.
+<p class="level0"><a name="28"></a><span class="nroffip">28</span>
+<p class="level1">Operation timeout. The specified time-out period was reached according to the conditions.
+<p class="level0"><a name="30"></a><span class="nroffip">30</span>
+<p class="level1">FTP PORT failed. The PORT command failed. Not all FTP servers support the PORT command, try doing a transfer using PASV instead!
+<p class="level0"><a name="31"></a><span class="nroffip">31</span>
+<p class="level1">FTP couldn't use REST. The REST command failed. This command is used for resumed FTP transfers.
+<p class="level0"><a name="33"></a><span class="nroffip">33</span>
+<p class="level1">HTTP range error. The range "command" didn't work.
+<p class="level0"><a name="34"></a><span class="nroffip">34</span>
+<p class="level1">HTTP post error. Internal post-request generation error.
+<p class="level0"><a name="35"></a><span class="nroffip">35</span>
+<p class="level1">SSL connect error. The SSL handshaking failed.
+<p class="level0"><a name="36"></a><span class="nroffip">36</span>
+<p class="level1">FTP bad download resume. Couldn't continue an earlier aborted download.
+<p class="level0"><a name="37"></a><span class="nroffip">37</span>
+<p class="level1">FILE couldn't read file. Failed to open the file. Permissions?
+<p class="level0"><a name="38"></a><span class="nroffip">38</span>
+<p class="level1">LDAP cannot bind. LDAP bind operation failed.
+<p class="level0"><a name="39"></a><span class="nroffip">39</span>
+<p class="level1">LDAP search failed.
+<p class="level0"><a name="41"></a><span class="nroffip">41</span>
+<p class="level1">Function not found. A required LDAP function was not found.
+<p class="level0"><a name="42"></a><span class="nroffip">42</span>
+<p class="level1">Aborted by callback. An application told curl to abort the operation.
+<p class="level0"><a name="43"></a><span class="nroffip">43</span>
+<p class="level1">Internal error. A function was called with a bad parameter.
+<p class="level0"><a name="45"></a><span class="nroffip">45</span>
+<p class="level1">Interface error. A specified outgoing interface could not be used.
+<p class="level0"><a name="47"></a><span class="nroffip">47</span>
+<p class="level1">Too many redirects. When following redirects, curl hit the maximum amount.
+<p class="level0"><a name="48"></a><span class="nroffip">48</span>
+<p class="level1">Unknown option specified to libcurl. This indicates that you passed a weird option to curl that was passed on to libcurl and rejected. Read up in the manual!
+<p class="level0"><a name="49"></a><span class="nroffip">49</span>
+<p class="level1">Malformed telnet option.
+<p class="level0"><a name="51"></a><span class="nroffip">51</span>
+<p class="level1">The peer's SSL certificate or SSH MD5 fingerprint was not OK.
+<p class="level0"><a name="52"></a><span class="nroffip">52</span>
+<p class="level1">The server didn't reply anything, which here is considered an error.
+<p class="level0"><a name="53"></a><span class="nroffip">53</span>
+<p class="level1">SSL crypto engine not found.
+<p class="level0"><a name="54"></a><span class="nroffip">54</span>
+<p class="level1">Cannot set SSL crypto engine as default.
+<p class="level0"><a name="55"></a><span class="nroffip">55</span>
+<p class="level1">Failed sending network data.
+<p class="level0"><a name="56"></a><span class="nroffip">56</span>
+<p class="level1">Failure in receiving network data.
+<p class="level0"><a name="58"></a><span class="nroffip">58</span>
+<p class="level1">Problem with the local certificate.
+<p class="level0"><a name="59"></a><span class="nroffip">59</span>
+<p class="level1">Couldn't use specified SSL cipher.
+<p class="level0"><a name="60"></a><span class="nroffip">60</span>
+<p class="level1">Peer certificate cannot be authenticated with known CA certificates.
+<p class="level0"><a name="61"></a><span class="nroffip">61</span>
+<p class="level1">Unrecognized transfer encoding.
+<p class="level0"><a name="62"></a><span class="nroffip">62</span>
+<p class="level1">Invalid LDAP URL.
+<p class="level0"><a name="63"></a><span class="nroffip">63</span>
+<p class="level1">Maximum file size exceeded.
+<p class="level0"><a name="64"></a><span class="nroffip">64</span>
+<p class="level1">Requested FTP SSL level failed.
+<p class="level0"><a name="65"></a><span class="nroffip">65</span>
+<p class="level1">Sending the data requires a rewind that failed.
+<p class="level0"><a name="66"></a><span class="nroffip">66</span>
+<p class="level1">Failed to initialise SSL Engine.
+<p class="level0"><a name="67"></a><span class="nroffip">67</span>
+<p class="level1">The user name, password, or similar was not accepted and curl failed to log in.
+<p class="level0"><a name="68"></a><span class="nroffip">68</span>
+<p class="level1">File not found on TFTP server.
+<p class="level0"><a name="69"></a><span class="nroffip">69</span>
+<p class="level1">Permission problem on TFTP server.
+<p class="level0"><a name="70"></a><span class="nroffip">70</span>
+<p class="level1">Out of disk space on TFTP server.
+<p class="level0"><a name="71"></a><span class="nroffip">71</span>
+<p class="level1">Illegal TFTP operation.
+<p class="level0"><a name="72"></a><span class="nroffip">72</span>
+<p class="level1">Unknown TFTP transfer ID.
+<p class="level0"><a name="73"></a><span class="nroffip">73</span>
+<p class="level1">File already exists (TFTP).
+<p class="level0"><a name="74"></a><span class="nroffip">74</span>
+<p class="level1">No such user (TFTP).
+<p class="level0"><a name="75"></a><span class="nroffip">75</span>
+<p class="level1">Character conversion failed.
+<p class="level0"><a name="76"></a><span class="nroffip">76</span>
+<p class="level1">Character conversion functions required.
+<p class="level0"><a name="77"></a><span class="nroffip">77</span>
+<p class="level1">Problem with reading the SSL CA cert (path? access rights?).
+<p class="level0"><a name="78"></a><span class="nroffip">78</span>
+<p class="level1">The resource referenced in the URL does not exist.
+<p class="level0"><a name="79"></a><span class="nroffip">79</span>
+<p class="level1">An unspecified error occurred during the SSH session.
+<p class="level0"><a name="80"></a><span class="nroffip">80</span>
+<p class="level1">Failed to shut down the SSL connection.
+<p class="level0"><a name="82"></a><span class="nroffip">82</span>
+<p class="level1">Could not load CRL file, missing or wrong format (added in 7.19.0).
+<p class="level0"><a name="83"></a><span class="nroffip">83</span>
+<p class="level1">Issuer check failed (added in 7.19.0).
+<p class="level0"><a name="84"></a><span class="nroffip">84</span>
+<p class="level1">The FTP PRET command failed
+<p class="level0"><a name="85"></a><span class="nroffip">85</span>
+<p class="level1">RTSP: mismatch of CSeq numbers
+<p class="level0"><a name="86"></a><span class="nroffip">86</span>
+<p class="level1">RTSP: mismatch of Session Identifiers
+<p class="level0"><a name="87"></a><span class="nroffip">87</span>
+<p class="level1">unable to parse FTP file list
+<p class="level0"><a name="88"></a><span class="nroffip">88</span>
+<p class="level1">FTP chunk callback reported error
+<p class="level0"><a name="XX"></a><span class="nroffip">XX</span>
+<p class="level1">More error codes will appear here in future releases. The existing ones are meant to never change. <a name="AUTHORS"></a><h2 class="nroffsh">AUTHORS / CONTRIBUTORS</h2>
+<p class="level0">Daniel Stenberg is the main author, but the whole list of contributors is found in the separate THANKS file. <a name="WWW"></a><h2 class="nroffsh">WWW</h2>
+<p class="level0"><a href="http://curl.haxx.se">http://curl.haxx.se</a> <a name="FTP"></a><h2 class="nroffsh">FTP</h2>
+<p class="level0"><a href="ftp://ftp.sunet.se/pub/www/utilities/curl/">ftp://ftp.sunet.se/pub/www/utilities/curl/</a> <a name="SEE"></a><h2 class="nroffsh">SEE ALSO</h2>
+<p class="level0"><span Class="manpage">ftp (1)</span> <span Class="manpage">wget (1)</span> <p class="roffit">
+ This HTML page was made with <a href="http://daniel.haxx.se/projects/roffit/">roffit</a>.
+</body></html>
diff --git a/libs/libcurl/docs/curl.pdf b/libs/libcurl/docs/curl.pdf
new file mode 100644
index 0000000000..d990270390
--- /dev/null
+++ b/libs/libcurl/docs/curl.pdf
Binary files differ
diff --git a/libs/libcurl/docs/index.html b/libs/libcurl/docs/index.html
new file mode 100644
index 0000000000..4390378afd
--- /dev/null
+++ b/libs/libcurl/docs/index.html
@@ -0,0 +1,20 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
+<title>Index to Curl documentation</title>
+</head>
+
+<body>
+<h1 align="center">Index to Curl documentation</h1>
+
+<h2>Programs</h2>
+<a href="curl-config.html">curl-config</A>
+<br><a href="curl.html">curl</A>
+
+<h2>Tutorial</h2>
+<a href="TheArtOfHttpScripting">The Art Of Scripting HTTP Requests Using Curl</a> (plain text)
+
+<h2>libcurl</h2>
+See the <a href="libcurl/index.html">libcurl section</a>
+
+</body></html>
diff --git a/libs/libcurl/docs/mk-ca-bundle.1 b/libs/libcurl/docs/mk-ca-bundle.1
new file mode 100644
index 0000000000..c2f9f0c76a
--- /dev/null
+++ b/libs/libcurl/docs/mk-ca-bundle.1
@@ -0,0 +1,70 @@
+.\" **************************************************************************
+.\" * _ _ ____ _
+.\" * Project ___| | | | _ \| |
+.\" * / __| | | | |_) | |
+.\" * | (__| |_| | _ <| |___
+.\" * \___|\___/|_| \_\_____|
+.\" *
+.\" * Copyright (C) 2008 - 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.
+.\" *
+.\" **************************************************************************
+.\"
+.TH mk-ca-bundle 1 "5 Jan 2013" "version 1.17" "mk-ca-bundle manual"
+.SH NAME
+mk-ca-bundle \- convert mozilla's certdata.txt to PEM format
+.SH SYNOPSIS
+mk-ca-bundle [bilnqtuv]
+.I [outputfile]
+.SH DESCRIPTION
+The mk-ca-bundle tool downloads the certdata.txt file from Mozilla's source
+tree over HTTP, then parses certdata.txt and extracts CA Root Certificates
+into PEM format. These are then processed with the OpenSSL commandline tool
+to produce the final ca-bundle file.
+
+The default \fIoutputfile\fP name is \fBca-bundle.crt\fP. By setting it to '-'
+(a single dash) you will get the output sent to STDOUT instead of a file.
+
+The PEM format this scripts uses for output makes the result readily available
+for use by just about all OpenSSL or GnuTLS powered applications, such as
+curl, wget and more.
+.SH OPTIONS
+The following options are supported:
+.IP -b
+backup an existing version of \fIoutputfilename\fP
+.IP -f
+force rebuild even if certdata.txt is current (Added in version 1.17)
+.IP -i
+print version info about used modules
+.IP -l
+print license info about certdata.txt
+.IP -n
+no download of certdata.txt (to use existing)
+.IP -q
+be really quiet (no progress output at all)
+.IP -t
+include plain text listing of certificates
+.IP -u
+unlink (remove) certdata.txt after processing
+.IP -v
+be verbose and print out processed CAs
+.SH EXIT STATUS
+Returns 0 on success. Returns 1 if it fails to download data.
+.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>.
diff --git a/libs/libcurl/docs/mk-ca-bundle.html b/libs/libcurl/docs/mk-ca-bundle.html
new file mode 100644
index 0000000000..fbdd58957a
--- /dev/null
+++ b/libs/libcurl/docs/mk-ca-bundle.html
@@ -0,0 +1,82 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
+ "http://www.w3.org/TR/html4/loose.dtd">
+<html><head>
+<title>mk-ca-bundle man page</title>
+<meta name="generator" content="roffit">
+<STYLE type="text/css">
+P.level0 {
+ padding-left: 2em;
+}
+
+P.level1 {
+ padding-left: 4em;
+}
+
+P.level2 {
+ padding-left: 6em;
+}
+
+span.emphasis {
+ font-style: italic;
+}
+
+span.bold {
+ font-weight: bold;
+}
+
+span.manpage {
+ font-weight: bold;
+}
+
+h2.nroffsh {
+ background-color: #e0e0e0;
+}
+
+span.nroffip {
+ font-weight: bold;
+ font-size: 120%;
+ font-family: monospace;
+}
+
+p.roffit {
+ text-align: center;
+ font-size: 80%;
+}
+</STYLE>
+</head><body>
+
+<p class="level0"><a name="NAME"></a><h2 class="nroffsh">NAME</h2>
+<p class="level0">mk-ca-bundle - convert mozilla's certdata.txt to PEM format <a name="SYNOPSIS"></a><h2 class="nroffsh">SYNOPSIS</h2>
+<p class="level0">mk-ca-bundle [bilnqtuv] <span Class="emphasis">[outputfile]</span> <a name="DESCRIPTION"></a><h2 class="nroffsh">DESCRIPTION</h2>
+<p class="level0">The mk-ca-bundle tool downloads the certdata.txt file from Mozilla's source tree over HTTP, then parses certdata.txt and extracts CA Root Certificates into PEM format. These are then processed with the OpenSSL commandline tool to produce the final ca-bundle file.
+<p class="level0">The default <span Class="emphasis">outputfile</span> name is <span Class="bold">ca-bundle.crt</span>. By setting it to '-' (a single dash) you will get the output sent to STDOUT instead of a file.
+<p class="level0">The PEM format this scripts uses for output makes the result readily available for use by just about all OpenSSL or GnuTLS powered applications, such as curl, wget and more. <a name="OPTIONS"></a><h2 class="nroffsh">OPTIONS</h2>
+<p class="level0">The following options are supported:
+<p class="level0"><a name="-b"></a><span class="nroffip">-b</span>
+<p class="level1">backup an existing version of <span Class="emphasis">outputfilename</span>
+<p class="level0"><a name="-f"></a><span class="nroffip">-f</span>
+<p class="level1">force rebuild even if certdata.txt is current (Added in version 1.17)
+<p class="level0"><a name="-i"></a><span class="nroffip">-i</span>
+<p class="level1">print version info about used modules
+<p class="level0"><a name="-l"></a><span class="nroffip">-l</span>
+<p class="level1">print license info about certdata.txt
+<p class="level0"><a name="-n"></a><span class="nroffip">-n</span>
+<p class="level1">no download of certdata.txt (to use existing)
+<p class="level0"><a name="-q"></a><span class="nroffip">-q</span>
+<p class="level1">be really quiet (no progress output at all)
+<p class="level0"><a name="-t"></a><span class="nroffip">-t</span>
+<p class="level1">include plain text listing of certificates
+<p class="level0"><a name="-u"></a><span class="nroffip">-u</span>
+<p class="level1">unlink (remove) certdata.txt after processing
+<p class="level0"><a name="-v"></a><span class="nroffip">-v</span>
+<p class="level1">be verbose and print out processed CAs <a name="EXIT"></a><h2 class="nroffsh">EXIT STATUS</h2>
+<p class="level0">Returns 0 on success. Returns 1 if it fails to download data. <a name="CERTDATA"></a><h2 class="nroffsh">CERTDATA FORMAT</h2>
+<p class="level0">The file format used by Mozilla for this trust information seems to be documented here: <pre>
+<p class="level0"><a href="http://p11-glue.freedesktop.org/doc/storing-trust-policy/storing-trust-existing.html">http://p11-glue.freedesktop.org/doc/storing-trust-policy/storing-trust-existing.html</a>
+ </pre>
+
+<p class="level0"><a name="SEE"></a><h2 class="nroffsh">SEE ALSO</h2>
+<p class="level0"><span Class="manpage">curl (1)</span> <a name="HISTORY"></a><h2 class="nroffsh">HISTORY</h2>
+<p class="level0"><span Class="bold">mk-ca-bundle</span> is a command line tool that is shipped as part of every curl and libcurl release (see <a href="http://curl.haxx.se/">http://curl.haxx.se/</a>). 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 initially written by Jan Schaumann &lt;jschauma@netmeister.org&gt;. <p class="roffit">
+ This HTML page was made with <a href="http://daniel.haxx.se/projects/roffit/">roffit</a>.
+</body></html>
diff --git a/libs/libcurl/docs/mk-ca-bundle.pdf b/libs/libcurl/docs/mk-ca-bundle.pdf
new file mode 100644
index 0000000000..aa11a96672
--- /dev/null
+++ b/libs/libcurl/docs/mk-ca-bundle.pdf
Binary files differ
diff --git a/libs/libcurl/include/README b/libs/libcurl/include/README
new file mode 100644
index 0000000000..3e52a1d0a6
--- /dev/null
+++ b/libs/libcurl/include/README
@@ -0,0 +1,55 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+Include files for libcurl, external users.
+
+They're all placed in the curl subdirectory here for better fit in any kind
+of environment. You must include files from here using...
+
+ #include <curl/curl.h>
+
+... style and point the compiler's include path to the directory holding the
+curl subdirectory. It makes it more likely to survive future modifications.
+
+NOTE FOR LIBCURL HACKERS
+
+The following notes apply to libcurl version 7.19.0 and later.
+
+* The distributed curl/curlbuild.h file is only intended to be used on systems
+ which can not run the also distributed configure script.
+
+* The distributed curlbuild.h file is generated as a copy of curlbuild.h.dist
+ when the libcurl source code distribution archive file is originally created.
+
+* If you check out from git on a non-configure platform, you must run the
+ appropriate buildconf* script to set up curlbuild.h and other local files
+ before being able of compiling the library.
+
+* On systems capable of running the configure script, the configure process
+ will overwrite the distributed include/curl/curlbuild.h file with one that
+ is suitable and specific to the library being configured and built, which
+ is generated from the include/curl/curlbuild.h.in template file.
+
+* If you intend to distribute an already compiled libcurl library you _MUST_
+ also distribute along with it the generated curl/curlbuild.h which has been
+ used to compile it. Otherwise the library will be of no use for the users of
+ the library that you have built. It is _your_ responsibility to provide this
+ file. No one at the cURL project can know how you have built the library.
+
+* File curl/curlbuild.h includes platform and configuration dependent info,
+ and must not be modified by anyone. Configure script generates it for you.
+
+* We cannot assume anything else but very basic compiler features being
+ present. While libcurl requires an ANSI C compiler to build, some of the
+ earlier ANSI compilers clearly can't deal with some preprocessor operators.
+
+* Newlines must remain unix-style for older compilers' sake.
+
+* Comments must be written in the old-style /* unnested C-fashion */
+
+To figure out how to do good and portable checks for features, operating
+systems or specific hardwarare, a very good resource is Bjorn Reese's
+collection at http://predef.sf.net/
diff --git a/libs/libcurl/include/curl/curl.h b/libs/libcurl/include/curl/curl.h
new file mode 100644
index 0000000000..4e09cf7288
--- /dev/null
+++ b/libs/libcurl/include/curl/curl.h
@@ -0,0 +1,2268 @@
+#ifndef __CURL_CURL_H
+#define __CURL_CURL_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.
+ *
+ ***************************************************************************/
+
+/*
+ * If you have libcurl problems, all docs and details are found here:
+ * http://curl.haxx.se/libcurl/
+ *
+ * curl-library mailing list subscription and unsubscription web interface:
+ * http://cool.haxx.se/mailman/listinfo/curl-library/
+ */
+
+#include "curlver.h" /* libcurl version defines */
+#include "curlbuild.h" /* libcurl build definitions */
+#include "curlrules.h" /* libcurl rules enforcement */
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && \
+ !defined(WIN32) && !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+#include <stdio.h>
+#include <limits.h>
+
+#if defined(__FreeBSD__) && (__FreeBSD__ >= 2)
+/* Needed for __FreeBSD_version symbol definition */
+#include <osreldate.h>
+#endif
+
+/* The include stuff here below is mainly for time_t! */
+#include <sys/types.h>
+#include <time.h>
+
+#if defined(WIN32) && !defined(_WIN32_WCE) && !defined(__CYGWIN__)
+#if !(defined(_WINSOCKAPI_) || defined(_WINSOCK_H) || defined(__LWIP_OPT_H__))
+/* The check above prevents the winsock2 inclusion if winsock.h already was
+ included, since they can't co-exist without problems */
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#endif
+#endif
+
+/* HP-UX systems version 9, 10 and 11 lack sys/select.h and so does oldish
+ libc5-based Linux systems. Only include it on systems that are known to
+ require it! */
+#if defined(_AIX) || defined(__NOVELL_LIBC__) || defined(__NetBSD__) || \
+ defined(__minix) || defined(__SYMBIAN32__) || defined(__INTEGRITY) || \
+ defined(ANDROID) || defined(__ANDROID__) || \
+ (defined(__FreeBSD_version) && (__FreeBSD_version < 800000))
+#include <sys/select.h>
+#endif
+
+#if !defined(WIN32) && !defined(_WIN32_WCE)
+#include <sys/socket.h>
+#endif
+
+#if !defined(WIN32) && !defined(__WATCOMC__) && !defined(__VXWORKS__)
+#include <sys/time.h>
+#endif
+
+#ifdef __BEOS__
+#include <support/SupportDefs.h>
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void CURL;
+
+/*
+ * libcurl external API function linkage decorations.
+ */
+
+#ifdef CURL_STATICLIB
+# define CURL_EXTERN
+#elif defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__)
+# if defined(BUILDING_LIBCURL)
+# define CURL_EXTERN __declspec(dllexport)
+# else
+# define CURL_EXTERN __declspec(dllimport)
+# endif
+#elif defined(BUILDING_LIBCURL) && defined(CURL_HIDDEN_SYMBOLS)
+# define CURL_EXTERN CURL_EXTERN_SYMBOL
+#else
+# define CURL_EXTERN
+#endif
+
+#ifndef curl_socket_typedef
+/* socket typedef */
+#if defined(WIN32) && !defined(__LWIP_OPT_H__)
+typedef SOCKET curl_socket_t;
+#define CURL_SOCKET_BAD INVALID_SOCKET
+#else
+typedef int curl_socket_t;
+#define CURL_SOCKET_BAD -1
+#endif
+#define curl_socket_typedef
+#endif /* curl_socket_typedef */
+
+struct curl_httppost {
+ struct curl_httppost *next; /* next entry in the list */
+ char *name; /* pointer to allocated name */
+ long namelength; /* length of name length */
+ char *contents; /* pointer to allocated data contents */
+ long contentslength; /* length of contents field */
+ char *buffer; /* pointer to allocated buffer contents */
+ long bufferlength; /* length of buffer field */
+ char *contenttype; /* Content-Type */
+ struct curl_slist* contentheader; /* list of extra headers for this form */
+ struct curl_httppost *more; /* if one field name has more than one
+ file, this link should link to following
+ files */
+ long flags; /* as defined below */
+#define HTTPPOST_FILENAME (1<<0) /* specified content is a file name */
+#define HTTPPOST_READFILE (1<<1) /* specified content is a file name */
+#define HTTPPOST_PTRNAME (1<<2) /* name is only stored pointer
+ do not free in formfree */
+#define HTTPPOST_PTRCONTENTS (1<<3) /* contents is only stored pointer
+ do not free in formfree */
+#define HTTPPOST_BUFFER (1<<4) /* upload file from buffer */
+#define HTTPPOST_PTRBUFFER (1<<5) /* upload file from pointer contents */
+#define HTTPPOST_CALLBACK (1<<6) /* upload file contents by using the
+ regular read callback to get the data
+ and pass the given pointer as custom
+ pointer */
+
+ char *showfilename; /* The file name to show. If not set, the
+ actual file name will be used (if this
+ is a file part) */
+ void *userp; /* custom pointer used for
+ 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.
+ We do the ifndef check to allow this value to easier be changed at build
+ time for those who feel adventurous. The practical minimum is about
+ 400 bytes since libcurl uses a buffer of this size as a scratch area
+ (unrelated to network send operations). */
+#define CURL_MAX_WRITE_SIZE 16384
+#endif
+
+#ifndef CURL_MAX_HTTP_HEADER
+/* The only reason to have a max limit for this is to avoid the risk of a bad
+ server feeding libcurl with a never-ending header that will cause reallocs
+ infinitely */
+#define CURL_MAX_HTTP_HEADER (100*1024)
+#endif
+
+/* This is a magic return code for the write callback that, when returned,
+ will signal libcurl to pause receiving on the current transfer. */
+#define CURL_WRITEFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_write_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *outstream);
+
+
+
+/* enumeration of file types */
+typedef enum {
+ CURLFILETYPE_FILE = 0,
+ CURLFILETYPE_DIRECTORY,
+ CURLFILETYPE_SYMLINK,
+ CURLFILETYPE_DEVICE_BLOCK,
+ CURLFILETYPE_DEVICE_CHAR,
+ CURLFILETYPE_NAMEDPIPE,
+ CURLFILETYPE_SOCKET,
+ CURLFILETYPE_DOOR, /* is possible only on Sun Solaris now */
+
+ CURLFILETYPE_UNKNOWN /* should never occur */
+} curlfiletype;
+
+#define CURLFINFOFLAG_KNOWN_FILENAME (1<<0)
+#define CURLFINFOFLAG_KNOWN_FILETYPE (1<<1)
+#define CURLFINFOFLAG_KNOWN_TIME (1<<2)
+#define CURLFINFOFLAG_KNOWN_PERM (1<<3)
+#define CURLFINFOFLAG_KNOWN_UID (1<<4)
+#define CURLFINFOFLAG_KNOWN_GID (1<<5)
+#define CURLFINFOFLAG_KNOWN_SIZE (1<<6)
+#define CURLFINFOFLAG_KNOWN_HLINKCOUNT (1<<7)
+
+/* Content of this structure depends on information which is known and is
+ achievable (e.g. by FTP LIST parsing). Please see the url_easy_setopt(3) man
+ page for callbacks returning this structure -- some fields are mandatory,
+ some others are optional. The FLAG field has special meaning. */
+struct curl_fileinfo {
+ char *filename;
+ curlfiletype filetype;
+ time_t time;
+ unsigned int perm;
+ int uid;
+ int gid;
+ curl_off_t size;
+ long int hardlinks;
+
+ struct {
+ /* If some of these fields is not NULL, it is a pointer to b_data. */
+ char *time;
+ char *perm;
+ char *user;
+ char *group;
+ char *target; /* pointer to the target filename of a symlink */
+ } strings;
+
+ unsigned int flags;
+
+ /* used internally */
+ char * b_data;
+ size_t b_size;
+ size_t b_used;
+};
+
+/* return codes for CURLOPT_CHUNK_BGN_FUNCTION */
+#define CURL_CHUNK_BGN_FUNC_OK 0
+#define CURL_CHUNK_BGN_FUNC_FAIL 1 /* tell the lib to end the task */
+#define CURL_CHUNK_BGN_FUNC_SKIP 2 /* skip this chunk over */
+
+/* if splitting of data transfer is enabled, this callback is called before
+ download of an individual chunk started. Note that parameter "remains" works
+ only for FTP wildcard downloading (for now), otherwise is not used */
+typedef long (*curl_chunk_bgn_callback)(const void *transfer_info,
+ void *ptr,
+ int remains);
+
+/* return codes for CURLOPT_CHUNK_END_FUNCTION */
+#define CURL_CHUNK_END_FUNC_OK 0
+#define CURL_CHUNK_END_FUNC_FAIL 1 /* tell the lib to end the task */
+
+/* If splitting of data transfer is enabled this callback is called after
+ download of an individual chunk finished.
+ Note! After this callback was set then it have to be called FOR ALL chunks.
+ Even if downloading of this chunk was skipped in CHUNK_BGN_FUNC.
+ This is the reason why we don't need "transfer_info" parameter in this
+ callback and we are not interested in "remains" parameter too. */
+typedef long (*curl_chunk_end_callback)(void *ptr);
+
+/* return codes for FNMATCHFUNCTION */
+#define CURL_FNMATCHFUNC_MATCH 0 /* string corresponds to the pattern */
+#define CURL_FNMATCHFUNC_NOMATCH 1 /* pattern doesn't match the string */
+#define CURL_FNMATCHFUNC_FAIL 2 /* an error occurred */
+
+/* callback type for wildcard downloading pattern matching. If the
+ string matches the pattern, return CURL_FNMATCHFUNC_MATCH value, etc. */
+typedef int (*curl_fnmatch_callback)(void *ptr,
+ const char *pattern,
+ const char *string);
+
+/* These are the return codes for the seek callbacks */
+#define CURL_SEEKFUNC_OK 0
+#define CURL_SEEKFUNC_FAIL 1 /* fail the entire transfer */
+#define CURL_SEEKFUNC_CANTSEEK 2 /* tell libcurl seeking can't be done, so
+ libcurl might try other means instead */
+typedef int (*curl_seek_callback)(void *instream,
+ curl_off_t offset,
+ int origin); /* 'whence' */
+
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to immediately abort the current transfer. */
+#define CURL_READFUNC_ABORT 0x10000000
+/* This is a return code for the read callback that, when returned, will
+ signal libcurl to pause sending data on the current transfer. */
+#define CURL_READFUNC_PAUSE 0x10000001
+
+typedef size_t (*curl_read_callback)(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *instream);
+
+typedef enum {
+ CURLSOCKTYPE_IPCXN, /* socket created for a specific IP connection */
+ CURLSOCKTYPE_ACCEPT, /* socket created by accept() call */
+ CURLSOCKTYPE_LAST /* never use */
+} curlsocktype;
+
+/* The return code from the sockopt_callback can signal information back
+ to libcurl: */
+#define CURL_SOCKOPT_OK 0
+#define CURL_SOCKOPT_ERROR 1 /* causes libcurl to abort and return
+ CURLE_ABORTED_BY_CALLBACK */
+#define CURL_SOCKOPT_ALREADY_CONNECTED 2
+
+typedef int (*curl_sockopt_callback)(void *clientp,
+ curl_socket_t curlfd,
+ curlsocktype purpose);
+
+struct curl_sockaddr {
+ int family;
+ int socktype;
+ int protocol;
+ unsigned int addrlen; /* addrlen was a socklen_t type before 7.18.0 but it
+ turned really ugly and painful on the systems that
+ lack this type */
+ struct sockaddr addr;
+};
+
+typedef curl_socket_t
+(*curl_opensocket_callback)(void *clientp,
+ curlsocktype purpose,
+ struct curl_sockaddr *address);
+
+typedef int
+(*curl_closesocket_callback)(void *clientp, curl_socket_t item);
+
+typedef enum {
+ CURLIOE_OK, /* I/O operation successful */
+ CURLIOE_UNKNOWNCMD, /* command was unknown to callback */
+ CURLIOE_FAILRESTART, /* failed to restart the read */
+ CURLIOE_LAST /* never use */
+} curlioerr;
+
+typedef enum {
+ CURLIOCMD_NOP, /* no operation */
+ CURLIOCMD_RESTARTREAD, /* restart the read stream from start */
+ CURLIOCMD_LAST /* never use */
+} curliocmd;
+
+typedef curlioerr (*curl_ioctl_callback)(CURL *handle,
+ int cmd,
+ void *clientp);
+
+/*
+ * The following typedef's are signatures of malloc, free, realloc, strdup and
+ * calloc respectively. Function pointers of these types can be passed to the
+ * curl_global_init_mem() function to set user defined memory management
+ * callback routines.
+ */
+typedef void *(*curl_malloc_callback)(size_t size);
+typedef void (*curl_free_callback)(void *ptr);
+typedef void *(*curl_realloc_callback)(void *ptr, size_t size);
+typedef char *(*curl_strdup_callback)(const char *str);
+typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size);
+
+/* the kind of data that is passed to information_callback*/
+typedef enum {
+ CURLINFO_TEXT = 0,
+ CURLINFO_HEADER_IN, /* 1 */
+ CURLINFO_HEADER_OUT, /* 2 */
+ CURLINFO_DATA_IN, /* 3 */
+ CURLINFO_DATA_OUT, /* 4 */
+ CURLINFO_SSL_DATA_IN, /* 5 */
+ CURLINFO_SSL_DATA_OUT, /* 6 */
+ CURLINFO_END
+} curl_infotype;
+
+typedef int (*curl_debug_callback)
+ (CURL *handle, /* the handle/transfer this concerns */
+ curl_infotype type, /* what kind of data */
+ char *data, /* points to the data */
+ size_t size, /* size of the data pointed to */
+ void *userptr); /* whatever the user please */
+
+/* All possible error codes from all sorts of curl functions. Future versions
+ may return other values, stay prepared.
+
+ Always add new return codes last. Never *EVER* remove any. The return
+ codes must remain the same!
+ */
+
+typedef enum {
+ CURLE_OK = 0,
+ CURLE_UNSUPPORTED_PROTOCOL, /* 1 */
+ CURLE_FAILED_INIT, /* 2 */
+ CURLE_URL_MALFORMAT, /* 3 */
+ CURLE_NOT_BUILT_IN, /* 4 - [was obsoleted in August 2007 for
+ 7.17.0, reused in April 2011 for 7.21.5] */
+ CURLE_COULDNT_RESOLVE_PROXY, /* 5 */
+ CURLE_COULDNT_RESOLVE_HOST, /* 6 */
+ CURLE_COULDNT_CONNECT, /* 7 */
+ CURLE_FTP_WEIRD_SERVER_REPLY, /* 8 */
+ CURLE_REMOTE_ACCESS_DENIED, /* 9 a service was denied by the server
+ due to lack of access - when login fails
+ this is not returned. */
+ CURLE_FTP_ACCEPT_FAILED, /* 10 - [was obsoleted in April 2006 for
+ 7.15.4, reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASS_REPLY, /* 11 */
+ CURLE_FTP_ACCEPT_TIMEOUT, /* 12 - timeout occurred accepting server
+ [was obsoleted in August 2007 for 7.17.0,
+ reused in Dec 2011 for 7.24.0]*/
+ CURLE_FTP_WEIRD_PASV_REPLY, /* 13 */
+ CURLE_FTP_WEIRD_227_FORMAT, /* 14 */
+ CURLE_FTP_CANT_GET_HOST, /* 15 */
+ CURLE_OBSOLETE16, /* 16 - NOT USED */
+ CURLE_FTP_COULDNT_SET_TYPE, /* 17 */
+ CURLE_PARTIAL_FILE, /* 18 */
+ CURLE_FTP_COULDNT_RETR_FILE, /* 19 */
+ CURLE_OBSOLETE20, /* 20 - NOT USED */
+ CURLE_QUOTE_ERROR, /* 21 - quote command failure */
+ CURLE_HTTP_RETURNED_ERROR, /* 22 */
+ CURLE_WRITE_ERROR, /* 23 */
+ CURLE_OBSOLETE24, /* 24 - NOT USED */
+ CURLE_UPLOAD_FAILED, /* 25 - failed upload "command" */
+ CURLE_READ_ERROR, /* 26 - couldn't open/read from file */
+ CURLE_OUT_OF_MEMORY, /* 27 */
+ /* Note: CURLE_OUT_OF_MEMORY may sometimes indicate a conversion error
+ instead of a memory allocation error if CURL_DOES_CONVERSIONS
+ is defined
+ */
+ CURLE_OPERATION_TIMEDOUT, /* 28 - the timeout time was reached */
+ CURLE_OBSOLETE29, /* 29 - NOT USED */
+ CURLE_FTP_PORT_FAILED, /* 30 - FTP PORT operation failed */
+ CURLE_FTP_COULDNT_USE_REST, /* 31 - the REST command failed */
+ CURLE_OBSOLETE32, /* 32 - NOT USED */
+ CURLE_RANGE_ERROR, /* 33 - RANGE "command" didn't work */
+ CURLE_HTTP_POST_ERROR, /* 34 */
+ CURLE_SSL_CONNECT_ERROR, /* 35 - wrong when connecting with SSL */
+ CURLE_BAD_DOWNLOAD_RESUME, /* 36 - couldn't resume download */
+ CURLE_FILE_COULDNT_READ_FILE, /* 37 */
+ CURLE_LDAP_CANNOT_BIND, /* 38 */
+ CURLE_LDAP_SEARCH_FAILED, /* 39 */
+ CURLE_OBSOLETE40, /* 40 - NOT USED */
+ CURLE_FUNCTION_NOT_FOUND, /* 41 */
+ CURLE_ABORTED_BY_CALLBACK, /* 42 */
+ CURLE_BAD_FUNCTION_ARGUMENT, /* 43 */
+ CURLE_OBSOLETE44, /* 44 - NOT USED */
+ CURLE_INTERFACE_FAILED, /* 45 - CURLOPT_INTERFACE failed */
+ CURLE_OBSOLETE46, /* 46 - NOT USED */
+ CURLE_TOO_MANY_REDIRECTS , /* 47 - catch endless re-direct loops */
+ CURLE_UNKNOWN_OPTION, /* 48 - User specified an unknown option */
+ CURLE_TELNET_OPTION_SYNTAX , /* 49 - Malformed telnet option */
+ CURLE_OBSOLETE50, /* 50 - NOT USED */
+ CURLE_PEER_FAILED_VERIFICATION, /* 51 - peer's certificate or fingerprint
+ wasn't verified fine */
+ CURLE_GOT_NOTHING, /* 52 - when this is a specific error */
+ CURLE_SSL_ENGINE_NOTFOUND, /* 53 - SSL crypto engine not found */
+ CURLE_SSL_ENGINE_SETFAILED, /* 54 - can not set SSL crypto engine as
+ default */
+ CURLE_SEND_ERROR, /* 55 - failed sending network data */
+ CURLE_RECV_ERROR, /* 56 - failure in receiving network data */
+ CURLE_OBSOLETE57, /* 57 - NOT IN USE */
+ CURLE_SSL_CERTPROBLEM, /* 58 - problem with the local certificate */
+ CURLE_SSL_CIPHER, /* 59 - couldn't use specified cipher */
+ CURLE_SSL_CACERT, /* 60 - problem with the CA cert (path?) */
+ CURLE_BAD_CONTENT_ENCODING, /* 61 - Unrecognized/bad encoding */
+ CURLE_LDAP_INVALID_URL, /* 62 - Invalid LDAP URL */
+ CURLE_FILESIZE_EXCEEDED, /* 63 - Maximum file size exceeded */
+ CURLE_USE_SSL_FAILED, /* 64 - Requested FTP SSL level failed */
+ CURLE_SEND_FAIL_REWIND, /* 65 - Sending the data requires a rewind
+ that failed */
+ CURLE_SSL_ENGINE_INITFAILED, /* 66 - failed to initialise ENGINE */
+ CURLE_LOGIN_DENIED, /* 67 - user, password or similar was not
+ accepted and we failed to login */
+ CURLE_TFTP_NOTFOUND, /* 68 - file not found on server */
+ CURLE_TFTP_PERM, /* 69 - permission problem on server */
+ CURLE_REMOTE_DISK_FULL, /* 70 - out of disk space on server */
+ CURLE_TFTP_ILLEGAL, /* 71 - Illegal TFTP operation */
+ CURLE_TFTP_UNKNOWNID, /* 72 - Unknown transfer ID */
+ CURLE_REMOTE_FILE_EXISTS, /* 73 - File already exists */
+ CURLE_TFTP_NOSUCHUSER, /* 74 - No such user */
+ CURLE_CONV_FAILED, /* 75 - conversion failed */
+ CURLE_CONV_REQD, /* 76 - caller must register conversion
+ callbacks using curl_easy_setopt options
+ CURLOPT_CONV_FROM_NETWORK_FUNCTION,
+ CURLOPT_CONV_TO_NETWORK_FUNCTION, and
+ CURLOPT_CONV_FROM_UTF8_FUNCTION */
+ CURLE_SSL_CACERT_BADFILE, /* 77 - could not load CACERT file, missing
+ or wrong format */
+ CURLE_REMOTE_FILE_NOT_FOUND, /* 78 - remote file not found */
+ CURLE_SSH, /* 79 - error from the SSH layer, somewhat
+ generic so the error message will be of
+ interest when this has happened */
+
+ CURLE_SSL_SHUTDOWN_FAILED, /* 80 - Failed to shut down the SSL
+ connection */
+ CURLE_AGAIN, /* 81 - socket is not ready for send/recv,
+ wait till it's ready and try again (Added
+ in 7.18.2) */
+ CURLE_SSL_CRL_BADFILE, /* 82 - could not load CRL file, missing or
+ wrong format (Added in 7.19.0) */
+ CURLE_SSL_ISSUER_ERROR, /* 83 - Issuer check failed. (Added in
+ 7.19.0) */
+ CURLE_FTP_PRET_FAILED, /* 84 - a PRET command failed */
+ CURLE_RTSP_CSEQ_ERROR, /* 85 - mismatch of RTSP CSeq numbers */
+ CURLE_RTSP_SESSION_ERROR, /* 86 - mismatch of RTSP Session Ids */
+ CURLE_FTP_BAD_FILE_LIST, /* 87 - unable to parse FTP file list */
+ CURLE_CHUNK_FAILED, /* 88 - chunk callback reported error */
+ CURLE_NO_CONNECTION_AVAILABLE, /* 89 - No connection available, the
+ session will be queued */
+ CURL_LAST /* never use! */
+} CURLcode;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Previously obsoletes error codes re-used in 7.24.0 */
+#define CURLE_OBSOLETE10 CURLE_FTP_ACCEPT_FAILED
+#define CURLE_OBSOLETE12 CURLE_FTP_ACCEPT_TIMEOUT
+
+/* compatibility with older names */
+#define CURLOPT_ENCODING CURLOPT_ACCEPT_ENCODING
+
+/* The following were added in 7.21.5, April 2011 */
+#define CURLE_UNKNOWN_TELNET_OPTION CURLE_UNKNOWN_OPTION
+
+/* The following were added in 7.17.1 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_SSL_PEER_CERTIFICATE CURLE_PEER_FAILED_VERIFICATION
+
+/* The following were added in 7.17.0 */
+/* These are scheduled to disappear by 2009 */
+#define CURLE_OBSOLETE CURLE_OBSOLETE50 /* no one should be using this! */
+#define CURLE_BAD_PASSWORD_ENTERED CURLE_OBSOLETE46
+#define CURLE_BAD_CALLING_ORDER CURLE_OBSOLETE44
+#define CURLE_FTP_USER_PASSWORD_INCORRECT CURLE_OBSOLETE10
+#define CURLE_FTP_CANT_RECONNECT CURLE_OBSOLETE16
+#define CURLE_FTP_COULDNT_GET_SIZE CURLE_OBSOLETE32
+#define CURLE_FTP_COULDNT_SET_ASCII CURLE_OBSOLETE29
+#define CURLE_FTP_WEIRD_USER_REPLY CURLE_OBSOLETE12
+#define CURLE_FTP_WRITE_ERROR CURLE_OBSOLETE20
+#define CURLE_LIBRARY_NOT_FOUND CURLE_OBSOLETE40
+#define CURLE_MALFORMAT_USER CURLE_OBSOLETE24
+#define CURLE_SHARE_IN_USE CURLE_OBSOLETE57
+#define CURLE_URL_MALFORMAT_USER CURLE_NOT_BUILT_IN
+
+#define CURLE_FTP_ACCESS_DENIED CURLE_REMOTE_ACCESS_DENIED
+#define CURLE_FTP_COULDNT_SET_BINARY CURLE_FTP_COULDNT_SET_TYPE
+#define CURLE_FTP_QUOTE_ERROR CURLE_QUOTE_ERROR
+#define CURLE_TFTP_DISKFULL CURLE_REMOTE_DISK_FULL
+#define CURLE_TFTP_EXISTS CURLE_REMOTE_FILE_EXISTS
+#define CURLE_HTTP_RANGE_ERROR CURLE_RANGE_ERROR
+#define CURLE_FTP_SSL_FAILED CURLE_USE_SSL_FAILED
+
+/* The following were added earlier */
+
+#define CURLE_OPERATION_TIMEOUTED CURLE_OPERATION_TIMEDOUT
+
+#define CURLE_HTTP_NOT_FOUND CURLE_HTTP_RETURNED_ERROR
+#define CURLE_HTTP_PORT_FAILED CURLE_INTERFACE_FAILED
+#define CURLE_FTP_COULDNT_STOR_FILE CURLE_UPLOAD_FAILED
+
+#define CURLE_FTP_PARTIAL_FILE CURLE_PARTIAL_FILE
+#define CURLE_FTP_BAD_DOWNLOAD_RESUME CURLE_BAD_DOWNLOAD_RESUME
+
+/* This was the error code 50 in 7.7.3 and a few earlier versions, this
+ is no longer used by libcurl but is instead #defined here only to not
+ make programs break */
+#define CURLE_ALREADY_COMPLETE 99999
+
+#endif /*!CURL_NO_OLDIES*/
+
+/* This prototype applies to all conversion callbacks */
+typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length);
+
+typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, /* easy handle */
+ void *ssl_ctx, /* actually an
+ OpenSSL SSL_CTX */
+ void *userptr);
+
+typedef enum {
+ CURLPROXY_HTTP = 0, /* added in 7.10, new in 7.19.4 default is to use
+ CONNECT HTTP/1.1 */
+ CURLPROXY_HTTP_1_0 = 1, /* added in 7.19.4, force to use CONNECT
+ HTTP/1.0 */
+ CURLPROXY_SOCKS4 = 4, /* support added in 7.15.2, enum existed already
+ in 7.10 */
+ CURLPROXY_SOCKS5 = 5, /* added in 7.10 */
+ CURLPROXY_SOCKS4A = 6, /* added in 7.18.0 */
+ CURLPROXY_SOCKS5_HOSTNAME = 7 /* Use the SOCKS5 protocol but pass along the
+ host name rather than the IP address. added
+ in 7.18.0 */
+} curl_proxytype; /* this enum was added in 7.10 */
+
+/*
+ * Bitmasks for CURLOPT_HTTPAUTH and CURLOPT_PROXYAUTH options:
+ *
+ * CURLAUTH_NONE - No HTTP authentication
+ * CURLAUTH_BASIC - HTTP Basic authentication (default)
+ * CURLAUTH_DIGEST - HTTP Digest authentication
+ * CURLAUTH_GSSNEGOTIATE - HTTP GSS-Negotiate authentication
+ * CURLAUTH_NTLM - HTTP NTLM authentication
+ * CURLAUTH_DIGEST_IE - HTTP Digest authentication with IE flavour
+ * CURLAUTH_NTLM_WB - HTTP NTLM authentication delegated to winbind helper
+ * CURLAUTH_ONLY - Use together with a single other type to force no
+ * authentication or just that single type
+ * CURLAUTH_ANY - All fine types set
+ * CURLAUTH_ANYSAFE - All fine types except Basic
+ */
+
+#define CURLAUTH_NONE ((unsigned long)0)
+#define CURLAUTH_BASIC (((unsigned long)1)<<0)
+#define CURLAUTH_DIGEST (((unsigned long)1)<<1)
+#define CURLAUTH_GSSNEGOTIATE (((unsigned long)1)<<2)
+#define CURLAUTH_NTLM (((unsigned long)1)<<3)
+#define CURLAUTH_DIGEST_IE (((unsigned long)1)<<4)
+#define CURLAUTH_NTLM_WB (((unsigned long)1)<<5)
+#define CURLAUTH_ONLY (((unsigned long)1)<<31)
+#define CURLAUTH_ANY (~CURLAUTH_DIGEST_IE)
+#define CURLAUTH_ANYSAFE (~(CURLAUTH_BASIC|CURLAUTH_DIGEST_IE))
+
+#define CURLSSH_AUTH_ANY ~0 /* all types supported by the server */
+#define CURLSSH_AUTH_NONE 0 /* none allowed, silly but complete */
+#define CURLSSH_AUTH_PUBLICKEY (1<<0) /* public/private key files */
+#define CURLSSH_AUTH_PASSWORD (1<<1) /* password */
+#define CURLSSH_AUTH_HOST (1<<2) /* host key files */
+#define CURLSSH_AUTH_KEYBOARD (1<<3) /* keyboard interactive */
+#define CURLSSH_AUTH_AGENT (1<<4) /* agent (ssh-agent, pageant...) */
+#define CURLSSH_AUTH_DEFAULT CURLSSH_AUTH_ANY
+
+#define CURLGSSAPI_DELEGATION_NONE 0 /* no delegation (default) */
+#define CURLGSSAPI_DELEGATION_POLICY_FLAG (1<<0) /* if permitted by policy */
+#define CURLGSSAPI_DELEGATION_FLAG (1<<1) /* delegate always */
+
+#define CURL_ERROR_SIZE 256
+
+enum curl_khtype {
+ CURLKHTYPE_UNKNOWN,
+ CURLKHTYPE_RSA1,
+ CURLKHTYPE_RSA,
+ CURLKHTYPE_DSS
+};
+
+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
+ callback */
+enum curl_khstat {
+ CURLKHSTAT_FINE_ADD_TO_FILE,
+ CURLKHSTAT_FINE,
+ CURLKHSTAT_REJECT, /* reject the connection, return an error */
+ CURLKHSTAT_DEFER, /* do not accept it, but we can't answer right now so
+ this causes a CURLE_DEFER error but otherwise the
+ connection will be left intact etc */
+ CURLKHSTAT_LAST /* not for use, only a marker for last-in-list */
+};
+
+/* this is the set of status codes pass in to the callback */
+enum curl_khmatch {
+ CURLKHMATCH_OK, /* match */
+ CURLKHMATCH_MISMATCH, /* host found, key mismatch! */
+ CURLKHMATCH_MISSING, /* no matching host/key found */
+ CURLKHMATCH_LAST /* not for use, only a marker for last-in-list */
+};
+
+typedef int
+ (*curl_sshkeycallback) (CURL *easy, /* easy handle */
+ const struct curl_khkey *knownkey, /* known */
+ const struct curl_khkey *foundkey, /* found */
+ enum curl_khmatch, /* libcurl's view on the keys */
+ void *clientp); /* custom pointer passed from app */
+
+/* parameter for the CURLOPT_USE_SSL option */
+typedef enum {
+ CURLUSESSL_NONE, /* do not attempt to use SSL */
+ CURLUSESSL_TRY, /* try using SSL, proceed anyway otherwise */
+ CURLUSESSL_CONTROL, /* SSL for the control connection or fail */
+ CURLUSESSL_ALL, /* SSL for all communication or fail */
+ CURLUSESSL_LAST /* not an option, never use */
+} curl_usessl;
+
+/* Definition of bits for the CURLOPT_SSL_OPTIONS argument: */
+
+/* - ALLOW_BEAST tells libcurl to allow the BEAST SSL vulnerability in the
+ name of improving interoperability with older servers. Some SSL libraries
+ have introduced work-arounds for this flaw but those work-arounds sometimes
+ make the SSL communication fail. To regain functionality with those broken
+ servers, a user can this way allow the vulnerability back. */
+#define CURLSSLOPT_ALLOW_BEAST (1<<0)
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2009 */
+
+#define CURLFTPSSL_NONE CURLUSESSL_NONE
+#define CURLFTPSSL_TRY CURLUSESSL_TRY
+#define CURLFTPSSL_CONTROL CURLUSESSL_CONTROL
+#define CURLFTPSSL_ALL CURLUSESSL_ALL
+#define CURLFTPSSL_LAST CURLUSESSL_LAST
+#define curl_ftpssl curl_usessl
+#endif /*!CURL_NO_OLDIES*/
+
+/* parameter for the CURLOPT_FTP_SSL_CCC option */
+typedef enum {
+ CURLFTPSSL_CCC_NONE, /* do not send CCC */
+ CURLFTPSSL_CCC_PASSIVE, /* Let the server initiate the shutdown */
+ CURLFTPSSL_CCC_ACTIVE, /* Initiate the shutdown */
+ CURLFTPSSL_CCC_LAST /* not an option, never use */
+} curl_ftpccc;
+
+/* parameter for the CURLOPT_FTPSSLAUTH option */
+typedef enum {
+ CURLFTPAUTH_DEFAULT, /* let libcurl decide */
+ CURLFTPAUTH_SSL, /* use "AUTH SSL" */
+ CURLFTPAUTH_TLS, /* use "AUTH TLS" */
+ CURLFTPAUTH_LAST /* not an option, never use */
+} curl_ftpauth;
+
+/* parameter for the CURLOPT_FTP_CREATE_MISSING_DIRS option */
+typedef enum {
+ CURLFTP_CREATE_DIR_NONE, /* do NOT create missing dirs! */
+ CURLFTP_CREATE_DIR, /* (FTP/SFTP) if CWD fails, try MKD and then CWD
+ again if MKD succeeded, for SFTP this does
+ similar magic */
+ CURLFTP_CREATE_DIR_RETRY, /* (FTP only) if CWD fails, try MKD and then CWD
+ again even if MKD failed! */
+ CURLFTP_CREATE_DIR_LAST /* not an option, never use */
+} curl_ftpcreatedir;
+
+/* parameter for the CURLOPT_FTP_FILEMETHOD option */
+typedef enum {
+ CURLFTPMETHOD_DEFAULT, /* let libcurl pick */
+ CURLFTPMETHOD_MULTICWD, /* single CWD operation for each path part */
+ CURLFTPMETHOD_NOCWD, /* no CWD at all */
+ CURLFTPMETHOD_SINGLECWD, /* one CWD to full dir, then work on file */
+ CURLFTPMETHOD_LAST /* not an option, never use */
+} curl_ftpmethod;
+
+/* CURLPROTO_ defines are for the CURLOPT_*PROTOCOLS options */
+#define CURLPROTO_HTTP (1<<0)
+#define CURLPROTO_HTTPS (1<<1)
+#define CURLPROTO_FTP (1<<2)
+#define CURLPROTO_FTPS (1<<3)
+#define CURLPROTO_SCP (1<<4)
+#define CURLPROTO_SFTP (1<<5)
+#define CURLPROTO_TELNET (1<<6)
+#define CURLPROTO_LDAP (1<<7)
+#define CURLPROTO_LDAPS (1<<8)
+#define CURLPROTO_DICT (1<<9)
+#define CURLPROTO_FILE (1<<10)
+#define CURLPROTO_TFTP (1<<11)
+#define CURLPROTO_IMAP (1<<12)
+#define CURLPROTO_IMAPS (1<<13)
+#define CURLPROTO_POP3 (1<<14)
+#define CURLPROTO_POP3S (1<<15)
+#define CURLPROTO_SMTP (1<<16)
+#define CURLPROTO_SMTPS (1<<17)
+#define CURLPROTO_RTSP (1<<18)
+#define CURLPROTO_RTMP (1<<19)
+#define CURLPROTO_RTMPT (1<<20)
+#define CURLPROTO_RTMPE (1<<21)
+#define CURLPROTO_RTMPTE (1<<22)
+#define CURLPROTO_RTMPS (1<<23)
+#define CURLPROTO_RTMPTS (1<<24)
+#define CURLPROTO_GOPHER (1<<25)
+#define CURLPROTO_ALL (~0) /* enable everything */
+
+/* long may be 32 or 64 bits, but we should never depend on anything else
+ but 32 */
+#define CURLOPTTYPE_LONG 0
+#define CURLOPTTYPE_OBJECTPOINT 10000
+#define CURLOPTTYPE_FUNCTIONPOINT 20000
+#define CURLOPTTYPE_OFF_T 30000
+
+/* name is uppercase CURLOPT_<name>,
+ type is one of the defined CURLOPTTYPE_<type>
+ number is unique identifier */
+#ifdef CINIT
+#undef CINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CINIT(na,t,nu) CURLOPT_ ## na = CURLOPTTYPE_ ## t + nu
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLOPT_/**/name = type + number
+#endif
+
+/*
+ * This macro-mania below setups the CURLOPT_[what] enum, to be used with
+ * curl_easy_setopt(). The first argument in the CINIT() macro is the [what]
+ * word.
+ */
+
+typedef enum {
+ /* This is the FILE * or void * the regular output should be written to. */
+ CINIT(FILE, OBJECTPOINT, 1),
+
+ /* The full URL to get/put */
+ CINIT(URL, OBJECTPOINT, 2),
+
+ /* Port number to connect to, if other than default. */
+ CINIT(PORT, LONG, 3),
+
+ /* Name of proxy to use. */
+ CINIT(PROXY, OBJECTPOINT, 4),
+
+ /* "name:password" to use when fetching. */
+ CINIT(USERPWD, OBJECTPOINT, 5),
+
+ /* "name:password" to use with proxy. */
+ CINIT(PROXYUSERPWD, OBJECTPOINT, 6),
+
+ /* Range to get, specified as an ASCII string. */
+ CINIT(RANGE, OBJECTPOINT, 7),
+
+ /* not used */
+
+ /* Specified file stream to upload from (use as input): */
+ CINIT(INFILE, OBJECTPOINT, 9),
+
+ /* Buffer to receive error messages in, must be at least CURL_ERROR_SIZE
+ * bytes big. If this is not used, error messages go to stderr instead: */
+ CINIT(ERRORBUFFER, OBJECTPOINT, 10),
+
+ /* Function that will be called to store the output (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(WRITEFUNCTION, FUNCTIONPOINT, 11),
+
+ /* Function that will be called to read the input (instead of fread). The
+ * parameters will use fread() syntax, make sure to follow them. */
+ CINIT(READFUNCTION, FUNCTIONPOINT, 12),
+
+ /* Time-out the read operation after this amount of seconds */
+ CINIT(TIMEOUT, LONG, 13),
+
+ /* If the CURLOPT_INFILE is used, this can be used to inform libcurl about
+ * how large the file being sent really is. That allows better error
+ * checking and better verifies that the upload was successful. -1 means
+ * unknown size.
+ *
+ * For large file support, there is also a _LARGE version of the key
+ * which takes an off_t type, allowing platforms with larger off_t
+ * sizes to handle larger files. See below for INFILESIZE_LARGE.
+ */
+ CINIT(INFILESIZE, LONG, 14),
+
+ /* POST static input fields. */
+ CINIT(POSTFIELDS, OBJECTPOINT, 15),
+
+ /* Set the referrer page (needed by some CGIs) */
+ CINIT(REFERER, OBJECTPOINT, 16),
+
+ /* Set the FTP PORT string (interface name, named or numerical IP address)
+ Use i.e '-' to use default address. */
+ CINIT(FTPPORT, OBJECTPOINT, 17),
+
+ /* Set the User-Agent string (examined by some CGIs) */
+ CINIT(USERAGENT, OBJECTPOINT, 18),
+
+ /* If the download receives less than "low speed limit" bytes/second
+ * during "low speed time" seconds, the operations is aborted.
+ * You could i.e if you have a pretty high speed connection, abort if
+ * it is less than 2000 bytes/sec during 20 seconds.
+ */
+
+ /* Set the "low speed limit" */
+ CINIT(LOW_SPEED_LIMIT, LONG, 19),
+
+ /* Set the "low speed time" */
+ CINIT(LOW_SPEED_TIME, LONG, 20),
+
+ /* Set the continuation offset.
+ *
+ * Note there is also a _LARGE version of this key which uses
+ * off_t types, allowing for large file offsets on platforms which
+ * use larger-than-32-bit off_t's. Look below for RESUME_FROM_LARGE.
+ */
+ CINIT(RESUME_FROM, LONG, 21),
+
+ /* Set cookie in request: */
+ CINIT(COOKIE, OBJECTPOINT, 22),
+
+ /* This points to a linked list of headers, struct curl_slist kind */
+ CINIT(HTTPHEADER, OBJECTPOINT, 23),
+
+ /* This points to a linked list of post entries, struct curl_httppost */
+ CINIT(HTTPPOST, OBJECTPOINT, 24),
+
+ /* name of the file keeping your private SSL-certificate */
+ CINIT(SSLCERT, OBJECTPOINT, 25),
+
+ /* password for the SSL or SSH private key */
+ CINIT(KEYPASSWD, OBJECTPOINT, 26),
+
+ /* send TYPE parameter? */
+ CINIT(CRLF, LONG, 27),
+
+ /* send linked-list of QUOTE commands */
+ CINIT(QUOTE, OBJECTPOINT, 28),
+
+ /* send FILE * or void * to store headers to, if you use a callback it
+ is simply passed to the callback unmodified */
+ CINIT(WRITEHEADER, OBJECTPOINT, 29),
+
+ /* point to a file to read the initial cookies from, also enables
+ "cookie awareness" */
+ CINIT(COOKIEFILE, OBJECTPOINT, 31),
+
+ /* What version to specifically try to use.
+ See CURL_SSLVERSION defines below. */
+ CINIT(SSLVERSION, LONG, 32),
+
+ /* What kind of HTTP time condition to use, see defines */
+ CINIT(TIMECONDITION, LONG, 33),
+
+ /* Time to use with the above condition. Specified in number of seconds
+ since 1 Jan 1970 */
+ CINIT(TIMEVALUE, LONG, 34),
+
+ /* 35 = OBSOLETE */
+
+ /* Custom request, for customizing the get command like
+ HTTP: DELETE, TRACE and others
+ FTP: to use a different list command
+ */
+ CINIT(CUSTOMREQUEST, OBJECTPOINT, 36),
+
+ /* HTTP request, for odd commands like DELETE, TRACE and others */
+ CINIT(STDERR, OBJECTPOINT, 37),
+
+ /* 38 is not used */
+
+ /* send linked-list of post-transfer QUOTE commands */
+ CINIT(POSTQUOTE, OBJECTPOINT, 39),
+
+ CINIT(WRITEINFO, OBJECTPOINT, 40), /* DEPRECATED, do not use! */
+
+ CINIT(VERBOSE, LONG, 41), /* talk a lot */
+ CINIT(HEADER, LONG, 42), /* throw the header out too */
+ CINIT(NOPROGRESS, LONG, 43), /* shut off the progress meter */
+ CINIT(NOBODY, LONG, 44), /* use HEAD to get http document */
+ CINIT(FAILONERROR, LONG, 45), /* no output on http error codes >= 300 */
+ CINIT(UPLOAD, LONG, 46), /* this is an upload */
+ CINIT(POST, LONG, 47), /* HTTP POST method */
+ CINIT(DIRLISTONLY, LONG, 48), /* bare names when listing directories */
+
+ CINIT(APPEND, LONG, 50), /* Append instead of overwrite on upload! */
+
+ /* Specify whether to read the user+password from the .netrc or the URL.
+ * This must be one of the CURL_NETRC_* enums below. */
+ CINIT(NETRC, LONG, 51),
+
+ CINIT(FOLLOWLOCATION, LONG, 52), /* use Location: Luke! */
+
+ CINIT(TRANSFERTEXT, LONG, 53), /* transfer data in text/ASCII format */
+ CINIT(PUT, LONG, 54), /* HTTP PUT */
+
+ /* 55 = OBSOLETE */
+
+ /* 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 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),
+
+ /* Port of the proxy, can be set in the proxy string as well with:
+ "[host]:[port]" */
+ CINIT(PROXYPORT, LONG, 59),
+
+ /* size of the POST input data, if strlen() is not good to use */
+ CINIT(POSTFIELDSIZE, LONG, 60),
+
+ /* tunnel non-http operations through a HTTP proxy */
+ CINIT(HTTPPROXYTUNNEL, LONG, 61),
+
+ /* Set the interface string to use as outgoing network interface */
+ CINIT(INTERFACE, OBJECTPOINT, 62),
+
+ /* Set the krb4/5 security level, this also enables krb4/5 awareness. This
+ * is a string, 'clear', 'safe', 'confidential' or 'private'. If the string
+ * is set but doesn't match one of these, 'private' will be used. */
+ CINIT(KRBLEVEL, OBJECTPOINT, 63),
+
+ /* Set if we should verify the peer in ssl handshake, set 1 to verify. */
+ CINIT(SSL_VERIFYPEER, LONG, 64),
+
+ /* The CApath or CAfile used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAINFO, OBJECTPOINT, 65),
+
+ /* 66 = OBSOLETE */
+ /* 67 = OBSOLETE */
+
+ /* Maximum number of http redirects to follow */
+ CINIT(MAXREDIRS, LONG, 68),
+
+ /* Pass a long set to 1 to get the date of the requested document (if
+ possible)! Pass a zero to shut it off. */
+ CINIT(FILETIME, LONG, 69),
+
+ /* This points to a linked list of telnet options */
+ CINIT(TELNETOPTIONS, OBJECTPOINT, 70),
+
+ /* Max amount of cached alive connections */
+ CINIT(MAXCONNECTS, LONG, 71),
+
+ CINIT(CLOSEPOLICY, LONG, 72), /* DEPRECATED, do not use! */
+
+ /* 73 = OBSOLETE */
+
+ /* Set to explicitly use a new connection for the upcoming transfer.
+ Do not use this unless you're absolutely sure of this, as it makes the
+ operation slower and is less friendly for the network. */
+ CINIT(FRESH_CONNECT, LONG, 74),
+
+ /* Set to explicitly forbid the upcoming transfer's connection to be re-used
+ when done. Do not use this unless you're absolutely sure of this, as it
+ makes the operation slower and is less friendly for the network. */
+ CINIT(FORBID_REUSE, LONG, 75),
+
+ /* Set to a file name that contains random data for libcurl to use to
+ seed the random engine when doing SSL connects. */
+ CINIT(RANDOM_FILE, OBJECTPOINT, 76),
+
+ /* Set to the Entropy Gathering Daemon socket pathname */
+ CINIT(EGDSOCKET, OBJECTPOINT, 77),
+
+ /* Time-out connect operations after this amount of seconds, if connects are
+ OK within this time, then fine... This only aborts the connect phase. */
+ CINIT(CONNECTTIMEOUT, LONG, 78),
+
+ /* Function that will be called to store headers (instead of fwrite). The
+ * parameters will use fwrite() syntax, make sure to follow them. */
+ CINIT(HEADERFUNCTION, FUNCTIONPOINT, 79),
+
+ /* Set this to force the HTTP request to get back to GET. Only really usable
+ if POST, PUT or a custom request have been used first.
+ */
+ CINIT(HTTPGET, LONG, 80),
+
+ /* Set if we should verify the Common name from the peer certificate in ssl
+ * handshake, set 1 to check existence, 2 to ensure that it matches the
+ * provided hostname. */
+ CINIT(SSL_VERIFYHOST, LONG, 81),
+
+ /* Specify which file name to write all known cookies in after completed
+ operation. Set file name to "-" (dash) to make it go to stdout. */
+ CINIT(COOKIEJAR, OBJECTPOINT, 82),
+
+ /* Specify which SSL ciphers to use */
+ CINIT(SSL_CIPHER_LIST, OBJECTPOINT, 83),
+
+ /* Specify which HTTP version to use! This must be set to one of the
+ CURL_HTTP_VERSION* enums set below. */
+ CINIT(HTTP_VERSION, LONG, 84),
+
+ /* Specifically switch on or off the FTP engine's use of the EPSV command. By
+ default, that one will always be attempted before the more traditional
+ PASV command. */
+ CINIT(FTP_USE_EPSV, LONG, 85),
+
+ /* type of the file keeping your SSL-certificate ("DER", "PEM", "ENG") */
+ CINIT(SSLCERTTYPE, OBJECTPOINT, 86),
+
+ /* name of the file keeping your private SSL-key */
+ CINIT(SSLKEY, OBJECTPOINT, 87),
+
+ /* type of the file keeping your private SSL-key ("DER", "PEM", "ENG") */
+ CINIT(SSLKEYTYPE, OBJECTPOINT, 88),
+
+ /* crypto engine for the SSL-sub system */
+ CINIT(SSLENGINE, OBJECTPOINT, 89),
+
+ /* set the crypto engine for the SSL-sub system as default
+ the param has no meaning...
+ */
+ CINIT(SSLENGINE_DEFAULT, LONG, 90),
+
+ /* Non-zero value means to use the global dns cache */
+ CINIT(DNS_USE_GLOBAL_CACHE, LONG, 91), /* DEPRECATED, do not use! */
+
+ /* DNS cache timeout */
+ CINIT(DNS_CACHE_TIMEOUT, LONG, 92),
+
+ /* send linked-list of pre-transfer QUOTE commands */
+ CINIT(PREQUOTE, OBJECTPOINT, 93),
+
+ /* set the debug function */
+ CINIT(DEBUGFUNCTION, FUNCTIONPOINT, 94),
+
+ /* set the data for the debug function */
+ CINIT(DEBUGDATA, OBJECTPOINT, 95),
+
+ /* mark this as start of a cookie session */
+ CINIT(COOKIESESSION, LONG, 96),
+
+ /* The CApath directory used to validate the peer certificate
+ this option is used only if SSL_VERIFYPEER is true */
+ CINIT(CAPATH, OBJECTPOINT, 97),
+
+ /* Instruct libcurl to use a smaller receive buffer */
+ CINIT(BUFFERSIZE, LONG, 98),
+
+ /* Instruct libcurl to not use any signal/alarm handlers, even when using
+ timeouts. This option is useful for multi-threaded applications.
+ See libcurl-the-guide for more background information. */
+ CINIT(NOSIGNAL, LONG, 99),
+
+ /* Provide a CURLShare for mutexing non-ts data */
+ CINIT(SHARE, OBJECTPOINT, 100),
+
+ /* indicates type of proxy. accepted values are CURLPROXY_HTTP (default),
+ CURLPROXY_SOCKS4, CURLPROXY_SOCKS4A and CURLPROXY_SOCKS5. */
+ CINIT(PROXYTYPE, LONG, 101),
+
+ /* Set the Accept-Encoding string. Use this to tell a server you would like
+ the response to be compressed. Before 7.21.6, this was known as
+ CURLOPT_ENCODING */
+ CINIT(ACCEPT_ENCODING, OBJECTPOINT, 102),
+
+ /* Set pointer to private data */
+ CINIT(PRIVATE, OBJECTPOINT, 103),
+
+ /* Set aliases for HTTP 200 in the HTTP Response header */
+ CINIT(HTTP200ALIASES, OBJECTPOINT, 104),
+
+ /* Continue to send authentication (user+password) when following locations,
+ even when hostname changed. This can potentially send off the name
+ and password to whatever host the server decides. */
+ CINIT(UNRESTRICTED_AUTH, LONG, 105),
+
+ /* Specifically switch on or off the FTP engine's use of the EPRT command (
+ it also disables the LPRT attempt). By default, those ones will always be
+ attempted before the good old traditional PORT command. */
+ CINIT(FTP_USE_EPRT, LONG, 106),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_USERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(HTTPAUTH, LONG, 107),
+
+ /* Set the ssl context callback function, currently only for OpenSSL ssl_ctx
+ in second argument. The function must be matching the
+ curl_ssl_ctx_callback proto. */
+ CINIT(SSL_CTX_FUNCTION, FUNCTIONPOINT, 108),
+
+ /* Set the userdata for the ssl context callback function's third
+ argument */
+ CINIT(SSL_CTX_DATA, OBJECTPOINT, 109),
+
+ /* FTP Option that causes missing dirs to be created on the remote server.
+ In 7.19.4 we introduced the convenience enums for this option using the
+ CURLFTP_CREATE_DIR prefix.
+ */
+ CINIT(FTP_CREATE_MISSING_DIRS, LONG, 110),
+
+ /* Set this to a bitmask value to enable the particular authentications
+ methods you like. Use this in combination with CURLOPT_PROXYUSERPWD.
+ Note that setting multiple bits may cause extra network round-trips. */
+ CINIT(PROXYAUTH, LONG, 111),
+
+ /* FTP option that changes the timeout, in seconds, associated with
+ getting a response. This is different from transfer timeout time and
+ essentially places a demand on the FTP server to acknowledge commands
+ in a timely manner. */
+ CINIT(FTP_RESPONSE_TIMEOUT, LONG, 112),
+#define CURLOPT_SERVER_RESPONSE_TIMEOUT CURLOPT_FTP_RESPONSE_TIMEOUT
+
+ /* Set this option to one of the CURL_IPRESOLVE_* defines (see below) to
+ tell libcurl to resolve names to those IP versions only. This only has
+ affect on systems with support for more than one, i.e IPv4 _and_ IPv6. */
+ CINIT(IPRESOLVE, LONG, 113),
+
+ /* Set this option to limit the size of a file that will be downloaded from
+ an HTTP or FTP server.
+
+ Note there is also _LARGE version which adds large file support for
+ platforms which have larger off_t sizes. See MAXFILESIZE_LARGE below. */
+ CINIT(MAXFILESIZE, LONG, 114),
+
+ /* See the comment for INFILESIZE above, but in short, specifies
+ * the size of the file being uploaded. -1 means unknown.
+ */
+ CINIT(INFILESIZE_LARGE, OFF_T, 115),
+
+ /* Sets the continuation offset. There is also a LONG version of this;
+ * look above for RESUME_FROM.
+ */
+ CINIT(RESUME_FROM_LARGE, OFF_T, 116),
+
+ /* Sets the maximum size of data that will be downloaded from
+ * an HTTP or FTP server. See MAXFILESIZE above for the LONG version.
+ */
+ CINIT(MAXFILESIZE_LARGE, OFF_T, 117),
+
+ /* Set this option to the file name of your .netrc file you want libcurl
+ to parse (using the CURLOPT_NETRC option). If not set, libcurl will do
+ a poor attempt to find the user's home directory and check for a .netrc
+ file in there. */
+ CINIT(NETRC_FILE, OBJECTPOINT, 118),
+
+ /* Enable SSL/TLS for FTP, pick one of:
+ CURLUSESSL_TRY - try using SSL, proceed anyway otherwise
+ CURLUSESSL_CONTROL - SSL for the control connection or fail
+ CURLUSESSL_ALL - SSL for all communication or fail
+ */
+ CINIT(USE_SSL, LONG, 119),
+
+ /* The _LARGE version of the standard POSTFIELDSIZE option */
+ CINIT(POSTFIELDSIZE_LARGE, OFF_T, 120),
+
+ /* Enable/disable the TCP Nagle algorithm */
+ CINIT(TCP_NODELAY, LONG, 121),
+
+ /* 122 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 123 OBSOLETE. Gone in 7.16.0 */
+ /* 124 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 125 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 126 OBSOLETE, used in 7.12.3. Gone in 7.13.0 */
+ /* 127 OBSOLETE. Gone in 7.16.0 */
+ /* 128 OBSOLETE. Gone in 7.16.0 */
+
+ /* When FTP over SSL/TLS is selected (with CURLOPT_USE_SSL), this option
+ can be used to change libcurl's default action which is to first try
+ "AUTH SSL" and then "AUTH TLS" in this order, and proceed when a OK
+ response has been received.
+
+ Available parameters are:
+ CURLFTPAUTH_DEFAULT - let libcurl decide
+ CURLFTPAUTH_SSL - try "AUTH SSL" first, then TLS
+ CURLFTPAUTH_TLS - try "AUTH TLS" first, then SSL
+ */
+ CINIT(FTPSSLAUTH, LONG, 129),
+
+ CINIT(IOCTLFUNCTION, FUNCTIONPOINT, 130),
+ CINIT(IOCTLDATA, OBJECTPOINT, 131),
+
+ /* 132 OBSOLETE. Gone in 7.16.0 */
+ /* 133 OBSOLETE. Gone in 7.16.0 */
+
+ /* zero terminated string for pass on to the FTP server when asked for
+ "account" info */
+ CINIT(FTP_ACCOUNT, OBJECTPOINT, 134),
+
+ /* feed cookies into cookie engine */
+ CINIT(COOKIELIST, OBJECTPOINT, 135),
+
+ /* ignore Content-Length */
+ CINIT(IGNORE_CONTENT_LENGTH, LONG, 136),
+
+ /* Set to non-zero to skip the IP address received in a 227 PASV FTP server
+ response. Typically used for FTP-SSL purposes but is not restricted to
+ that. libcurl will then instead use the same IP address it used for the
+ control connection. */
+ CINIT(FTP_SKIP_PASV_IP, LONG, 137),
+
+ /* Select "file method" to use when doing FTP, see the curl_ftpmethod
+ above. */
+ CINIT(FTP_FILEMETHOD, LONG, 138),
+
+ /* Local port number to bind the socket to */
+ CINIT(LOCALPORT, LONG, 139),
+
+ /* Number of ports to try, including the first one set with LOCALPORT.
+ Thus, setting it to 1 will make no additional attempts but the first.
+ */
+ CINIT(LOCALPORTRANGE, LONG, 140),
+
+ /* no transfer, set up connection and let application use the socket by
+ extracting it with CURLINFO_LASTSOCKET */
+ CINIT(CONNECT_ONLY, LONG, 141),
+
+ /* Function that will be called to convert from the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_FROM_NETWORK_FUNCTION, FUNCTIONPOINT, 142),
+
+ /* Function that will be called to convert to the
+ network encoding (instead of using the iconv calls in libcurl) */
+ CINIT(CONV_TO_NETWORK_FUNCTION, FUNCTIONPOINT, 143),
+
+ /* Function that will be called to convert from UTF8
+ (instead of using the iconv calls in libcurl)
+ Note that this is used only for SSL certificate processing */
+ CINIT(CONV_FROM_UTF8_FUNCTION, FUNCTIONPOINT, 144),
+
+ /* if the connection proceeds too quickly then need to slow it down */
+ /* limit-rate: maximum number of bytes per second to send or receive */
+ CINIT(MAX_SEND_SPEED_LARGE, OFF_T, 145),
+ CINIT(MAX_RECV_SPEED_LARGE, OFF_T, 146),
+
+ /* Pointer to command string to send if USER/PASS fails. */
+ CINIT(FTP_ALTERNATIVE_TO_USER, OBJECTPOINT, 147),
+
+ /* callback function for setting socket options */
+ CINIT(SOCKOPTFUNCTION, FUNCTIONPOINT, 148),
+ CINIT(SOCKOPTDATA, OBJECTPOINT, 149),
+
+ /* set to 0 to disable session ID re-use for this transfer, default is
+ enabled (== 1) */
+ CINIT(SSL_SESSIONID_CACHE, LONG, 150),
+
+ /* allowed SSH authentication methods */
+ CINIT(SSH_AUTH_TYPES, LONG, 151),
+
+ /* Used by scp/sftp to do public/private key authentication */
+ CINIT(SSH_PUBLIC_KEYFILE, OBJECTPOINT, 152),
+ CINIT(SSH_PRIVATE_KEYFILE, OBJECTPOINT, 153),
+
+ /* Send CCC (Clear Command Channel) after authentication */
+ CINIT(FTP_SSL_CCC, LONG, 154),
+
+ /* Same as TIMEOUT and CONNECTTIMEOUT, but with ms resolution */
+ CINIT(TIMEOUT_MS, LONG, 155),
+ CINIT(CONNECTTIMEOUT_MS, LONG, 156),
+
+ /* set to zero to disable the libcurl's decoding and thus pass the raw body
+ data to the application even when it is encoded/compressed */
+ CINIT(HTTP_TRANSFER_DECODING, LONG, 157),
+ CINIT(HTTP_CONTENT_DECODING, LONG, 158),
+
+ /* Permission used when creating new files and directories on the remote
+ server for protocols that support it, SFTP/SCP/FILE */
+ CINIT(NEW_FILE_PERMS, LONG, 159),
+ CINIT(NEW_DIRECTORY_PERMS, LONG, 160),
+
+ /* Set the behaviour of POST when redirecting. Values must be set to one
+ of CURL_REDIR* defines below. This used to be called CURLOPT_POST301 */
+ CINIT(POSTREDIR, LONG, 161),
+
+ /* used by scp/sftp to verify the host's public key */
+ CINIT(SSH_HOST_PUBLIC_KEY_MD5, OBJECTPOINT, 162),
+
+ /* Callback function for opening socket (instead of socket(2)). Optionally,
+ callback is able change the address or refuse to connect returning
+ CURL_SOCKET_BAD. The callback should have type
+ curl_opensocket_callback */
+ CINIT(OPENSOCKETFUNCTION, FUNCTIONPOINT, 163),
+ CINIT(OPENSOCKETDATA, OBJECTPOINT, 164),
+
+ /* POST volatile input fields. */
+ CINIT(COPYPOSTFIELDS, OBJECTPOINT, 165),
+
+ /* set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy */
+ CINIT(PROXY_TRANSFER_MODE, LONG, 166),
+
+ /* Callback function for seeking in the input stream */
+ CINIT(SEEKFUNCTION, FUNCTIONPOINT, 167),
+ CINIT(SEEKDATA, OBJECTPOINT, 168),
+
+ /* CRL file */
+ CINIT(CRLFILE, OBJECTPOINT, 169),
+
+ /* Issuer certificate */
+ CINIT(ISSUERCERT, OBJECTPOINT, 170),
+
+ /* (IPv6) Address scope */
+ CINIT(ADDRESS_SCOPE, LONG, 171),
+
+ /* Collect certificate chain info and allow it to get retrievable with
+ CURLINFO_CERTINFO after the transfer is complete. (Unfortunately) only
+ working with OpenSSL-powered builds. */
+ CINIT(CERTINFO, LONG, 172),
+
+ /* "name" and "pwd" to use when fetching. */
+ CINIT(USERNAME, OBJECTPOINT, 173),
+ CINIT(PASSWORD, OBJECTPOINT, 174),
+
+ /* "name" and "pwd" to use with Proxy when fetching. */
+ CINIT(PROXYUSERNAME, OBJECTPOINT, 175),
+ CINIT(PROXYPASSWORD, OBJECTPOINT, 176),
+
+ /* Comma separated list of hostnames defining no-proxy zones. These should
+ match both hostnames directly, and hostnames within a domain. For
+ example, local.com will match local.com and www.local.com, but NOT
+ notlocal.com or www.notlocal.com. For compatibility with other
+ implementations of this, .local.com will be considered to be the same as
+ local.com. A single * is the only valid wildcard, and effectively
+ disables the use of proxy. */
+ CINIT(NOPROXY, OBJECTPOINT, 177),
+
+ /* block size for TFTP transfers */
+ CINIT(TFTP_BLKSIZE, LONG, 178),
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_SERVICE, OBJECTPOINT, 179),
+
+ /* Socks Service */
+ CINIT(SOCKS5_GSSAPI_NEC, LONG, 180),
+
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ CINIT(PROTOCOLS, LONG, 181),
+
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ CINIT(REDIR_PROTOCOLS, LONG, 182),
+
+ /* set the SSH knownhost file name to use */
+ CINIT(SSH_KNOWNHOSTS, OBJECTPOINT, 183),
+
+ /* set the SSH host key callback, must point to a curl_sshkeycallback
+ function */
+ CINIT(SSH_KEYFUNCTION, FUNCTIONPOINT, 184),
+
+ /* set the SSH host key callback custom pointer */
+ CINIT(SSH_KEYDATA, OBJECTPOINT, 185),
+
+ /* set the SMTP mail originator */
+ CINIT(MAIL_FROM, OBJECTPOINT, 186),
+
+ /* set the SMTP mail receiver(s) */
+ CINIT(MAIL_RCPT, OBJECTPOINT, 187),
+
+ /* FTP: send PRET before PASV */
+ CINIT(FTP_USE_PRET, LONG, 188),
+
+ /* RTSP request method (OPTIONS, SETUP, PLAY, etc...) */
+ CINIT(RTSP_REQUEST, LONG, 189),
+
+ /* The RTSP session identifier */
+ CINIT(RTSP_SESSION_ID, OBJECTPOINT, 190),
+
+ /* The RTSP stream URI */
+ CINIT(RTSP_STREAM_URI, OBJECTPOINT, 191),
+
+ /* The Transport: header to use in RTSP requests */
+ CINIT(RTSP_TRANSPORT, OBJECTPOINT, 192),
+
+ /* Manually initialize the client RTSP CSeq for this handle */
+ CINIT(RTSP_CLIENT_CSEQ, LONG, 193),
+
+ /* Manually initialize the server RTSP CSeq for this handle */
+ CINIT(RTSP_SERVER_CSEQ, LONG, 194),
+
+ /* The stream to pass to INTERLEAVEFUNCTION. */
+ CINIT(INTERLEAVEDATA, OBJECTPOINT, 195),
+
+ /* Let the application define a custom write method for RTP data */
+ CINIT(INTERLEAVEFUNCTION, FUNCTIONPOINT, 196),
+
+ /* Turn on wildcard matching */
+ CINIT(WILDCARDMATCH, LONG, 197),
+
+ /* Directory matching callback called before downloading of an
+ individual file (chunk) started */
+ CINIT(CHUNK_BGN_FUNCTION, FUNCTIONPOINT, 198),
+
+ /* Directory matching callback called after the file (chunk)
+ was downloaded, or skipped */
+ CINIT(CHUNK_END_FUNCTION, FUNCTIONPOINT, 199),
+
+ /* Change match (fnmatch-like) callback for wildcard matching */
+ CINIT(FNMATCH_FUNCTION, FUNCTIONPOINT, 200),
+
+ /* Let the application define custom chunk data pointer */
+ CINIT(CHUNK_DATA, OBJECTPOINT, 201),
+
+ /* FNMATCH_FUNCTION user pointer */
+ CINIT(FNMATCH_DATA, OBJECTPOINT, 202),
+
+ /* send linked-list of name:port:address sets */
+ CINIT(RESOLVE, OBJECTPOINT, 203),
+
+ /* Set a username for authenticated TLS */
+ CINIT(TLSAUTH_USERNAME, OBJECTPOINT, 204),
+
+ /* Set a password for authenticated TLS */
+ CINIT(TLSAUTH_PASSWORD, OBJECTPOINT, 205),
+
+ /* Set authentication type for authenticated TLS */
+ CINIT(TLSAUTH_TYPE, OBJECTPOINT, 206),
+
+ /* Set to 1 to enable the "TE:" header in HTTP requests to ask for
+ compressed transfer-encoded responses. Set to 0 to disable the use of TE:
+ in outgoing requests. The current default is 0, but it might change in a
+ future libcurl release.
+
+ libcurl will ask for the compressed methods it knows of, and if that
+ isn't any, it will not ask for transfer-encoding at all even if this
+ option is set to 1.
+
+ */
+ CINIT(TRANSFER_ENCODING, LONG, 207),
+
+ /* Callback function for closing socket (instead of close(2)). The callback
+ should have type curl_closesocket_callback */
+ CINIT(CLOSESOCKETFUNCTION, FUNCTIONPOINT, 208),
+ CINIT(CLOSESOCKETDATA, OBJECTPOINT, 209),
+
+ /* allow GSSAPI credential delegation */
+ CINIT(GSSAPI_DELEGATION, LONG, 210),
+
+ /* Set the name servers to use for DNS resolution */
+ CINIT(DNS_SERVERS, OBJECTPOINT, 211),
+
+ /* Time-out accept operations (currently for FTP only) after this amount
+ of miliseconds. */
+ CINIT(ACCEPTTIMEOUT_MS, LONG, 212),
+
+ /* Set TCP keepalive */
+ CINIT(TCP_KEEPALIVE, LONG, 213),
+
+ /* non-universal keepalive knobs (Linux, AIX, HP-UX, more) */
+ CINIT(TCP_KEEPIDLE, LONG, 214),
+ CINIT(TCP_KEEPINTVL, LONG, 215),
+
+ /* Enable/disable specific SSL features with a bitmask, see CURLSSLOPT_* */
+ CINIT(SSL_OPTIONS, LONG, 216),
+
+ /* 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;
+
+#ifndef CURL_NO_OLDIES /* define this to test if your app builds with all
+ the obsolete stuff removed! */
+
+/* Backwards compatibility with older names */
+/* These are scheduled to disappear by 2011 */
+
+/* This was added in version 7.19.1 */
+#define CURLOPT_POST301 CURLOPT_POSTREDIR
+
+/* These are scheduled to disappear by 2009 */
+
+/* The following were added in 7.17.0 */
+#define CURLOPT_SSLKEYPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_FTPAPPEND CURLOPT_APPEND
+#define CURLOPT_FTPLISTONLY CURLOPT_DIRLISTONLY
+#define CURLOPT_FTP_SSL CURLOPT_USE_SSL
+
+/* The following were added earlier */
+
+#define CURLOPT_SSLCERTPASSWD CURLOPT_KEYPASSWD
+#define CURLOPT_KRB4LEVEL CURLOPT_KRBLEVEL
+
+#else
+/* This is set if CURL_NO_OLDIES is defined at compile-time */
+#undef CURLOPT_DNS_USE_GLOBAL_CACHE /* soon obsolete */
+#endif
+
+
+ /* Below here follows defines for the CURLOPT_IPRESOLVE option. If a host
+ name resolves addresses using more than one IP protocol version, this
+ option might be handy to force libcurl to use a specific IP version. */
+#define CURL_IPRESOLVE_WHATEVER 0 /* default, resolves addresses to all IP
+ versions that your system allows */
+#define CURL_IPRESOLVE_V4 1 /* resolve to ipv4 addresses */
+#define CURL_IPRESOLVE_V6 2 /* resolve to ipv6 addresses */
+
+ /* three convenient "aliases" that follow the name scheme better */
+#define CURLOPT_WRITEDATA CURLOPT_FILE
+#define CURLOPT_READDATA CURLOPT_INFILE
+#define CURLOPT_HEADERDATA CURLOPT_WRITEHEADER
+#define CURLOPT_RTSPHEADER CURLOPT_HTTPHEADER
+
+ /* These enums are for use with the CURLOPT_HTTP_VERSION option. */
+enum {
+ CURL_HTTP_VERSION_NONE, /* setting this means we don't care, and that we'd
+ like the library to choose the best possible
+ 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 */
+};
+
+/*
+ * Public API enums for RTSP requests
+ */
+enum {
+ CURL_RTSPREQ_NONE, /* first in list */
+ CURL_RTSPREQ_OPTIONS,
+ CURL_RTSPREQ_DESCRIBE,
+ CURL_RTSPREQ_ANNOUNCE,
+ CURL_RTSPREQ_SETUP,
+ CURL_RTSPREQ_PLAY,
+ CURL_RTSPREQ_PAUSE,
+ CURL_RTSPREQ_TEARDOWN,
+ CURL_RTSPREQ_GET_PARAMETER,
+ CURL_RTSPREQ_SET_PARAMETER,
+ CURL_RTSPREQ_RECORD,
+ CURL_RTSPREQ_RECEIVE,
+ CURL_RTSPREQ_LAST /* last in list */
+};
+
+ /* These enums are for use with the CURLOPT_NETRC option. */
+enum CURL_NETRC_OPTION {
+ CURL_NETRC_IGNORED, /* The .netrc will never be read.
+ * This is the default. */
+ CURL_NETRC_OPTIONAL, /* A user:password in the URL will be preferred
+ * to one in the .netrc. */
+ CURL_NETRC_REQUIRED, /* A user:password in the URL will be ignored.
+ * Unless one is set programmatically, the .netrc
+ * will be queried. */
+ CURL_NETRC_LAST
+};
+
+enum {
+ CURL_SSLVERSION_DEFAULT,
+ CURL_SSLVERSION_TLSv1,
+ CURL_SSLVERSION_SSLv2,
+ CURL_SSLVERSION_SSLv3,
+
+ CURL_SSLVERSION_LAST /* never use, keep last */
+};
+
+enum CURL_TLSAUTH {
+ CURL_TLSAUTH_NONE,
+ CURL_TLSAUTH_SRP,
+ CURL_TLSAUTH_LAST /* never use, keep last */
+};
+
+/* symbols to use with CURLOPT_POSTREDIR.
+ CURL_REDIR_POST_301, CURL_REDIR_POST_302 and CURL_REDIR_POST_303
+ can be bitwise ORed so that CURL_REDIR_POST_301 | CURL_REDIR_POST_302
+ | CURL_REDIR_POST_303 == CURL_REDIR_POST_ALL */
+
+#define CURL_REDIR_GET_ALL 0
+#define CURL_REDIR_POST_301 1
+#define CURL_REDIR_POST_302 2
+#define CURL_REDIR_POST_303 4
+#define CURL_REDIR_POST_ALL \
+ (CURL_REDIR_POST_301|CURL_REDIR_POST_302|CURL_REDIR_POST_303)
+
+typedef enum {
+ CURL_TIMECOND_NONE,
+
+ CURL_TIMECOND_IFMODSINCE,
+ CURL_TIMECOND_IFUNMODSINCE,
+ CURL_TIMECOND_LASTMOD,
+
+ CURL_TIMECOND_LAST
+} curl_TimeCond;
+
+
+/* curl_strequal() and curl_strnequal() are subject for removal in a future
+ libcurl, see lib/README.curlx for details */
+CURL_EXTERN int (curl_strequal)(const char *s1, const char *s2);
+CURL_EXTERN int (curl_strnequal)(const char *s1, const char *s2, size_t n);
+
+/* name is uppercase CURLFORM_<name> */
+#ifdef CFINIT
+#undef CFINIT
+#endif
+
+#ifdef CURL_ISOCPP
+#define CFINIT(name) CURLFORM_ ## name
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define CFINIT(name) CURLFORM_/**/name
+#endif
+
+typedef enum {
+ CFINIT(NOTHING), /********* the first one is unused ************/
+
+ /* */
+ CFINIT(COPYNAME),
+ CFINIT(PTRNAME),
+ CFINIT(NAMELENGTH),
+ CFINIT(COPYCONTENTS),
+ CFINIT(PTRCONTENTS),
+ CFINIT(CONTENTSLENGTH),
+ CFINIT(FILECONTENT),
+ CFINIT(ARRAY),
+ CFINIT(OBSOLETE),
+ CFINIT(FILE),
+
+ CFINIT(BUFFER),
+ CFINIT(BUFFERPTR),
+ CFINIT(BUFFERLENGTH),
+
+ CFINIT(CONTENTTYPE),
+ CFINIT(CONTENTHEADER),
+ CFINIT(FILENAME),
+ CFINIT(END),
+ CFINIT(OBSOLETE2),
+
+ CFINIT(STREAM),
+
+ CURLFORM_LASTENTRY /* the last unused */
+} CURLformoption;
+
+#undef CFINIT /* done */
+
+/* structure to be used as parameter for CURLFORM_ARRAY */
+struct curl_forms {
+ CURLformoption option;
+ const char *value;
+};
+
+/* use this for multipart formpost building */
+/* Returns code for curl_formadd()
+ *
+ * Returns:
+ * CURL_FORMADD_OK on success
+ * CURL_FORMADD_MEMORY if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
+ * CURL_FORMADD_NULL if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY if a curl_httppost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
+ *
+ ***************************************************************************/
+typedef enum {
+ CURL_FORMADD_OK, /* first, no error */
+
+ CURL_FORMADD_MEMORY,
+ CURL_FORMADD_OPTION_TWICE,
+ CURL_FORMADD_NULL,
+ CURL_FORMADD_UNKNOWN_OPTION,
+ CURL_FORMADD_INCOMPLETE,
+ CURL_FORMADD_ILLEGAL_ARRAY,
+ CURL_FORMADD_DISABLED, /* libcurl was built with this disabled */
+
+ CURL_FORMADD_LAST /* last */
+} CURLFORMcode;
+
+/*
+ * NAME curl_formadd()
+ *
+ * DESCRIPTION
+ *
+ * Pretty advanced function for building multi-part formposts. Each invoke
+ * adds one part that together construct a full post. Then use
+ * CURLOPT_HTTPPOST to send it off to libcurl.
+ */
+CURL_EXTERN CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...);
+
+/*
+ * callback function for curl_formget()
+ * The void *arg pointer will be the one passed as second argument to
+ * curl_formget().
+ * The character buffer passed to it must not be freed.
+ * Should return the buffer length passed to it as the argument "len" on
+ * success.
+ */
+typedef size_t (*curl_formget_callback)(void *arg, const char *buf,
+ size_t len);
+
+/*
+ * NAME curl_formget()
+ *
+ * DESCRIPTION
+ *
+ * Serialize a curl_httppost struct built with curl_formadd().
+ * Accepts a void pointer as second argument which will be passed to
+ * the curl_formget_callback function.
+ * Returns 0 on success.
+ */
+CURL_EXTERN int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append);
+/*
+ * NAME curl_formfree()
+ *
+ * DESCRIPTION
+ *
+ * Free a multipart formpost previously built with curl_formadd().
+ */
+CURL_EXTERN void curl_formfree(struct curl_httppost *form);
+
+/*
+ * NAME curl_getenv()
+ *
+ * DESCRIPTION
+ *
+ * Returns a malloc()'ed string that MUST be curl_free()ed after usage is
+ * complete. DEPRECATED - see lib/README.curlx
+ */
+CURL_EXTERN char *curl_getenv(const char *variable);
+
+/*
+ * NAME curl_version()
+ *
+ * DESCRIPTION
+ *
+ * Returns a static ascii string of the libcurl version.
+ */
+CURL_EXTERN char *curl_version(void);
+
+/*
+ * NAME curl_easy_escape()
+ *
+ * DESCRIPTION
+ *
+ * Escapes URL strings (converts all letters consider illegal in URLs to their
+ * %XX versions). This function returns a new allocated string or NULL if an
+ * error occurred.
+ */
+CURL_EXTERN char *curl_easy_escape(CURL *handle,
+ const char *string,
+ int length);
+
+/* the previous version: */
+CURL_EXTERN char *curl_escape(const char *string,
+ int length);
+
+
+/*
+ * NAME curl_easy_unescape()
+ *
+ * DESCRIPTION
+ *
+ * Unescapes URL encoding in strings (converts all %XX codes to their 8bit
+ * versions). This function returns a new allocated string or NULL if an error
+ * occurred.
+ * Conversion Note: On non-ASCII platforms the ASCII %XX codes are
+ * converted into the host encoding.
+ */
+CURL_EXTERN char *curl_easy_unescape(CURL *handle,
+ const char *string,
+ int length,
+ int *outlength);
+
+/* the previous version */
+CURL_EXTERN char *curl_unescape(const char *string,
+ int length);
+
+/*
+ * NAME curl_free()
+ *
+ * DESCRIPTION
+ *
+ * Provided for de-allocation in the same translation unit that did the
+ * allocation. Added in libcurl 7.10
+ */
+CURL_EXTERN void curl_free(void *p);
+
+/*
+ * NAME curl_global_init()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() should be invoked exactly once for each application that
+ * uses libcurl and before any call of other libcurl functions.
+ *
+ * This function is not thread-safe!
+ */
+CURL_EXTERN CURLcode curl_global_init(long flags);
+
+/*
+ * NAME curl_global_init_mem()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_init() or curl_global_init_mem() should be invoked exactly once
+ * for each application that uses libcurl. This function can be used to
+ * initialize libcurl and set user defined memory management callback
+ * functions. Users can implement memory management routines to check for
+ * memory leaks, check for mis-use of the curl library etc. User registered
+ * callback routines with be invoked by this library instead of the system
+ * memory management routines like malloc, free etc.
+ */
+CURL_EXTERN CURLcode curl_global_init_mem(long flags,
+ curl_malloc_callback m,
+ curl_free_callback f,
+ curl_realloc_callback r,
+ curl_strdup_callback s,
+ curl_calloc_callback c);
+
+/*
+ * NAME curl_global_cleanup()
+ *
+ * DESCRIPTION
+ *
+ * curl_global_cleanup() should be invoked exactly once for each application
+ * that uses libcurl
+ */
+CURL_EXTERN void curl_global_cleanup(void);
+
+/* linked-list structure for the CURLOPT_QUOTE option (and other) */
+struct curl_slist {
+ char *data;
+ struct curl_slist *next;
+};
+
+/*
+ * NAME curl_slist_append()
+ *
+ * DESCRIPTION
+ *
+ * Appends a string to a linked list. If no list exists, it will be created
+ * first. Returns the new list, after appending.
+ */
+CURL_EXTERN struct curl_slist *curl_slist_append(struct curl_slist *,
+ const char *);
+
+/*
+ * NAME curl_slist_free_all()
+ *
+ * DESCRIPTION
+ *
+ * free a previously built curl_slist.
+ */
+CURL_EXTERN void curl_slist_free_all(struct curl_slist *);
+
+/*
+ * NAME curl_getdate()
+ *
+ * DESCRIPTION
+ *
+ * Returns the time, in seconds since 1 Jan 1970 of the time string given in
+ * the first argument. The time argument in the second parameter is unused
+ * and should be set to NULL.
+ */
+CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused);
+
+/* info about the certificate chain, only for OpenSSL builds. Asked
+ for with CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+struct curl_certinfo {
+ int num_of_certs; /* number of certificates with information */
+ struct curl_slist **certinfo; /* for each index in this array, there's a
+ linked list with textual information in the
+ format "name: value" */
+};
+
+#define CURLINFO_STRING 0x100000
+#define CURLINFO_LONG 0x200000
+#define CURLINFO_DOUBLE 0x300000
+#define CURLINFO_SLIST 0x400000
+#define CURLINFO_MASK 0x0fffff
+#define CURLINFO_TYPEMASK 0xf00000
+
+typedef enum {
+ CURLINFO_NONE, /* first, never use this */
+ CURLINFO_EFFECTIVE_URL = CURLINFO_STRING + 1,
+ CURLINFO_RESPONSE_CODE = CURLINFO_LONG + 2,
+ CURLINFO_TOTAL_TIME = CURLINFO_DOUBLE + 3,
+ CURLINFO_NAMELOOKUP_TIME = CURLINFO_DOUBLE + 4,
+ CURLINFO_CONNECT_TIME = CURLINFO_DOUBLE + 5,
+ CURLINFO_PRETRANSFER_TIME = CURLINFO_DOUBLE + 6,
+ CURLINFO_SIZE_UPLOAD = CURLINFO_DOUBLE + 7,
+ CURLINFO_SIZE_DOWNLOAD = CURLINFO_DOUBLE + 8,
+ CURLINFO_SPEED_DOWNLOAD = CURLINFO_DOUBLE + 9,
+ CURLINFO_SPEED_UPLOAD = CURLINFO_DOUBLE + 10,
+ CURLINFO_HEADER_SIZE = CURLINFO_LONG + 11,
+ CURLINFO_REQUEST_SIZE = CURLINFO_LONG + 12,
+ CURLINFO_SSL_VERIFYRESULT = CURLINFO_LONG + 13,
+ CURLINFO_FILETIME = CURLINFO_LONG + 14,
+ CURLINFO_CONTENT_LENGTH_DOWNLOAD = CURLINFO_DOUBLE + 15,
+ CURLINFO_CONTENT_LENGTH_UPLOAD = CURLINFO_DOUBLE + 16,
+ CURLINFO_STARTTRANSFER_TIME = CURLINFO_DOUBLE + 17,
+ CURLINFO_CONTENT_TYPE = CURLINFO_STRING + 18,
+ CURLINFO_REDIRECT_TIME = CURLINFO_DOUBLE + 19,
+ CURLINFO_REDIRECT_COUNT = CURLINFO_LONG + 20,
+ CURLINFO_PRIVATE = CURLINFO_STRING + 21,
+ CURLINFO_HTTP_CONNECTCODE = CURLINFO_LONG + 22,
+ CURLINFO_HTTPAUTH_AVAIL = CURLINFO_LONG + 23,
+ CURLINFO_PROXYAUTH_AVAIL = CURLINFO_LONG + 24,
+ CURLINFO_OS_ERRNO = CURLINFO_LONG + 25,
+ CURLINFO_NUM_CONNECTS = CURLINFO_LONG + 26,
+ CURLINFO_SSL_ENGINES = CURLINFO_SLIST + 27,
+ CURLINFO_COOKIELIST = CURLINFO_SLIST + 28,
+ CURLINFO_LASTSOCKET = CURLINFO_LONG + 29,
+ CURLINFO_FTP_ENTRY_PATH = CURLINFO_STRING + 30,
+ CURLINFO_REDIRECT_URL = CURLINFO_STRING + 31,
+ CURLINFO_PRIMARY_IP = CURLINFO_STRING + 32,
+ CURLINFO_APPCONNECT_TIME = CURLINFO_DOUBLE + 33,
+ CURLINFO_CERTINFO = CURLINFO_SLIST + 34,
+ CURLINFO_CONDITION_UNMET = CURLINFO_LONG + 35,
+ CURLINFO_RTSP_SESSION_ID = CURLINFO_STRING + 36,
+ CURLINFO_RTSP_CLIENT_CSEQ = CURLINFO_LONG + 37,
+ CURLINFO_RTSP_SERVER_CSEQ = CURLINFO_LONG + 38,
+ CURLINFO_RTSP_CSEQ_RECV = CURLINFO_LONG + 39,
+ CURLINFO_PRIMARY_PORT = CURLINFO_LONG + 40,
+ CURLINFO_LOCAL_IP = CURLINFO_STRING + 41,
+ CURLINFO_LOCAL_PORT = CURLINFO_LONG + 42,
+ /* Fill in new entries below here! */
+
+ CURLINFO_LASTONE = 42
+} CURLINFO;
+
+/* CURLINFO_RESPONSE_CODE is the new name for the option previously known as
+ CURLINFO_HTTP_CODE */
+#define CURLINFO_HTTP_CODE CURLINFO_RESPONSE_CODE
+
+typedef enum {
+ CURLCLOSEPOLICY_NONE, /* first, never use this */
+
+ CURLCLOSEPOLICY_OLDEST,
+ CURLCLOSEPOLICY_LEAST_RECENTLY_USED,
+ CURLCLOSEPOLICY_LEAST_TRAFFIC,
+ CURLCLOSEPOLICY_SLOWEST,
+ CURLCLOSEPOLICY_CALLBACK,
+
+ CURLCLOSEPOLICY_LAST /* last, never use this */
+} curl_closepolicy;
+
+#define CURL_GLOBAL_SSL (1<<0)
+#define CURL_GLOBAL_WIN32 (1<<1)
+#define CURL_GLOBAL_ALL (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32)
+#define CURL_GLOBAL_NOTHING 0
+#define CURL_GLOBAL_DEFAULT CURL_GLOBAL_ALL
+#define CURL_GLOBAL_ACK_EINTR (1<<2)
+
+
+/*****************************************************************************
+ * Setup defines, protos etc for the sharing stuff.
+ */
+
+/* Different data locks for a single share */
+typedef enum {
+ CURL_LOCK_DATA_NONE = 0,
+ /* CURL_LOCK_DATA_SHARE is used internally to say that
+ * the locking is just made to change the internal state of the share
+ * itself.
+ */
+ CURL_LOCK_DATA_SHARE,
+ CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_DATA_DNS,
+ CURL_LOCK_DATA_SSL_SESSION,
+ CURL_LOCK_DATA_CONNECT,
+ CURL_LOCK_DATA_LAST
+} curl_lock_data;
+
+/* Different lock access types */
+typedef enum {
+ CURL_LOCK_ACCESS_NONE = 0, /* unspecified action */
+ CURL_LOCK_ACCESS_SHARED = 1, /* for read perhaps */
+ CURL_LOCK_ACCESS_SINGLE = 2, /* for write perhaps */
+ CURL_LOCK_ACCESS_LAST /* never use */
+} curl_lock_access;
+
+typedef void (*curl_lock_function)(CURL *handle,
+ curl_lock_data data,
+ curl_lock_access locktype,
+ void *userptr);
+typedef void (*curl_unlock_function)(CURL *handle,
+ curl_lock_data data,
+ void *userptr);
+
+typedef void CURLSH;
+
+typedef enum {
+ CURLSHE_OK, /* all is fine */
+ CURLSHE_BAD_OPTION, /* 1 */
+ CURLSHE_IN_USE, /* 2 */
+ CURLSHE_INVALID, /* 3 */
+ CURLSHE_NOMEM, /* 4 out of memory */
+ CURLSHE_NOT_BUILT_IN, /* 5 feature not present in lib */
+ CURLSHE_LAST /* never use */
+} CURLSHcode;
+
+typedef enum {
+ CURLSHOPT_NONE, /* don't use */
+ CURLSHOPT_SHARE, /* specify a data type to share */
+ CURLSHOPT_UNSHARE, /* specify which data type to stop sharing */
+ CURLSHOPT_LOCKFUNC, /* pass in a 'curl_lock_function' pointer */
+ CURLSHOPT_UNLOCKFUNC, /* pass in a 'curl_unlock_function' pointer */
+ CURLSHOPT_USERDATA, /* pass in a user data pointer used in the lock/unlock
+ callback functions */
+ CURLSHOPT_LAST /* never use */
+} CURLSHoption;
+
+CURL_EXTERN CURLSH *curl_share_init(void);
+CURL_EXTERN CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...);
+CURL_EXTERN CURLSHcode curl_share_cleanup(CURLSH *);
+
+/****************************************************************************
+ * Structures for querying information about the curl library at runtime.
+ */
+
+typedef enum {
+ CURLVERSION_FIRST,
+ CURLVERSION_SECOND,
+ CURLVERSION_THIRD,
+ CURLVERSION_FOURTH,
+ CURLVERSION_LAST /* never actually use this */
+} CURLversion;
+
+/* The 'CURLVERSION_NOW' is the symbolic name meant to be used by
+ basically all programs ever that want to get version information. It is
+ meant to be a built-in version number for what kind of struct the caller
+ expects. If the struct ever changes, we redefine the NOW to another enum
+ from above. */
+#define CURLVERSION_NOW CURLVERSION_FOURTH
+
+typedef struct {
+ CURLversion age; /* age of the returned struct */
+ const char *version; /* LIBCURL_VERSION */
+ unsigned int version_num; /* LIBCURL_VERSION_NUM */
+ const char *host; /* OS/host/cpu/machine when configured */
+ int features; /* bitmask, see defines below */
+ const char *ssl_version; /* human readable string */
+ long ssl_version_num; /* not used anymore, always 0 */
+ const char *libz_version; /* human readable string */
+ /* protocols is terminated by an entry with a NULL protoname */
+ const char * const *protocols;
+
+ /* The fields below this were added in CURLVERSION_SECOND */
+ const char *ares;
+ int ares_num;
+
+ /* This field was added in CURLVERSION_THIRD */
+ const char *libidn;
+
+ /* These field were added in CURLVERSION_FOURTH */
+
+ /* Same as '_libiconv_version' if built with HAVE_ICONV */
+ int iconv_ver_num;
+
+ const char *libssh_version; /* human readable string */
+
+} curl_version_info_data;
+
+#define CURL_VERSION_IPV6 (1<<0) /* IPv6-enabled */
+#define CURL_VERSION_KERBEROS4 (1<<1) /* kerberos auth is supported */
+#define CURL_VERSION_SSL (1<<2) /* SSL options are present */
+#define CURL_VERSION_LIBZ (1<<3) /* libz features are present */
+#define CURL_VERSION_NTLM (1<<4) /* NTLM auth is supported */
+#define CURL_VERSION_GSSNEGOTIATE (1<<5) /* Negotiate auth support */
+#define CURL_VERSION_DEBUG (1<<6) /* built with debug capabilities */
+#define CURL_VERSION_ASYNCHDNS (1<<7) /* asynchronous dns resolves */
+#define CURL_VERSION_SPNEGO (1<<8) /* SPNEGO auth */
+#define CURL_VERSION_LARGEFILE (1<<9) /* supports files bigger than 2GB */
+#define CURL_VERSION_IDN (1<<10) /* International Domain Names support */
+#define CURL_VERSION_SSPI (1<<11) /* SSPI is supported */
+#define CURL_VERSION_CONV (1<<12) /* character conversions supported */
+#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()
+ *
+ * DESCRIPTION
+ *
+ * This function returns a pointer to a static copy of the version info
+ * struct. See above.
+ */
+CURL_EXTERN curl_version_info_data *curl_version_info(CURLversion);
+
+/*
+ * NAME curl_easy_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_strerror function may be used to turn a CURLcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_easy_strerror(CURLcode);
+
+/*
+ * NAME curl_share_strerror()
+ *
+ * DESCRIPTION
+ *
+ * The curl_share_strerror function may be used to turn a CURLSHcode value
+ * into the equivalent human readable error string. This is useful
+ * for printing meaningful error messages.
+ */
+CURL_EXTERN const char *curl_share_strerror(CURLSHcode);
+
+/*
+ * NAME curl_easy_pause()
+ *
+ * DESCRIPTION
+ *
+ * The curl_easy_pause function pauses or unpauses transfers. Select the new
+ * state by setting the bitmask, use the convenience defines below.
+ *
+ */
+CURL_EXTERN CURLcode curl_easy_pause(CURL *handle, int bitmask);
+
+#define CURLPAUSE_RECV (1<<0)
+#define CURLPAUSE_RECV_CONT (0)
+
+#define CURLPAUSE_SEND (1<<2)
+#define CURLPAUSE_SEND_CONT (0)
+
+#define CURLPAUSE_ALL (CURLPAUSE_RECV|CURLPAUSE_SEND)
+#define CURLPAUSE_CONT (CURLPAUSE_RECV_CONT|CURLPAUSE_SEND_CONT)
+
+#ifdef __cplusplus
+}
+#endif
+
+/* unfortunately, the easy.h and multi.h include files need options and info
+ stuff before they can be included! */
+#include "easy.h" /* nothing in curl is fun without the easy stuff */
+#include "multi.h"
+
+/* the typechecker doesn't work in C++ (yet) */
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && \
+ ((__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 3)) && \
+ !defined(__cplusplus) && !defined(CURL_DISABLE_TYPECHECK)
+#include "typecheck-gcc.h"
+#else
+#if defined(__STDC__) && (__STDC__ >= 1)
+/* This preprocessor magic that replaces a call with the exact same call is
+ only done to make sure application authors pass exactly three arguments
+ to these functions. */
+#define curl_easy_setopt(handle,opt,param) curl_easy_setopt(handle,opt,param)
+#define curl_easy_getinfo(handle,info,arg) curl_easy_getinfo(handle,info,arg)
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+#endif /* __STDC__ >= 1 */
+#endif /* gcc >= 4.3 && !__cplusplus */
+
+#endif /* __CURL_CURL_H */
diff --git a/libs/libcurl/include/curl/curlbuild.h b/libs/libcurl/include/curl/curlbuild.h
new file mode 100644
index 0000000000..3ad2f018d8
--- /dev/null
+++ b/libs/libcurl/include/curl/curlbuild.h
@@ -0,0 +1,585 @@
+#ifndef __CURL_CURLBUILD_H
+#define __CURL_CURLBUILD_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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* NOTES FOR CONFIGURE CAPABLE SYSTEMS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * See file include/curl/curlbuild.h.in, run configure, and forget
+ * that this file exists it is only used for non-configure systems.
+ * But you can keep reading if you want ;-)
+ *
+ */
+
+/* ================================================================ */
+/* NOTES FOR NON-CONFIGURE SYSTEMS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * If you think that something actually needs to be changed, adjusted
+ * or fixed in this file, then, report it on the libcurl development
+ * mailing list: http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * Try to keep one section per platform, compiler and architecture,
+ * otherwise, if an existing section is reused for a different one and
+ * later on the original is adjusted, probably the piggybacking one can
+ * be adversely changed.
+ *
+ * In order to differentiate between platforms/compilers/architectures
+ * use only compiler built in predefined preprocessor symbols.
+ *
+ * This header file shall only export symbols which are 'curl' or 'CURL'
+ * prefixed, otherwise public name space would be polluted.
+ *
+ * NOTE 2:
+ * -------
+ *
+ * For any given platform/compiler curl_off_t must be typedef'ed to a
+ * 64-bit wide signed integral data type. The width of this data type
+ * must remain constant and independent of any possible large file
+ * support settings.
+ *
+ * As an exception to the above, curl_off_t shall be typedef'ed to a
+ * 32-bit wide signed integral data type if there is no 64-bit type.
+ *
+ * As a general rule, curl_off_t shall not be mapped to off_t. This
+ * rule shall only be violated if off_t is the only 64-bit data type
+ * available and the size of off_t is independent of large file support
+ * settings. Keep your build on the safe side avoiding an off_t gating.
+ * If you have a 64-bit off_t then take for sure that another 64-bit
+ * data type exists, dig deeper and you will find it.
+ *
+ * NOTE 3:
+ * -------
+ *
+ * Right now you might be staring at file include/curl/curlbuild.h.dist or
+ * at file include/curl/curlbuild.h, this is due to the following reason:
+ * file include/curl/curlbuild.h.dist is renamed to include/curl/curlbuild.h
+ * when the libcurl source code distribution archive file is created.
+ *
+ * File include/curl/curlbuild.h.dist is not included in the distribution
+ * archive. File include/curl/curlbuild.h is not present in the git tree.
+ *
+ * The distributed include/curl/curlbuild.h file is only intended to be used
+ * on systems which can not run the also distributed configure script.
+ *
+ * On systems capable of running the configure script, the configure process
+ * will overwrite the distributed include/curl/curlbuild.h file with one that
+ * is suitable and specific to the library being configured and built, which
+ * is generated from the include/curl/curlbuild.h.in template file.
+ *
+ * If you check out from git on a non-configure platform, you must run the
+ * appropriate buildconf* script to set up curlbuild.h and other local files.
+ *
+ */
+
+/* ================================================================ */
+/* DEFINITION OF THESE SYMBOLS SHALL NOT TAKE PLACE ANYWHERE ELSE */
+/* ================================================================ */
+
+#ifdef CURL_SIZEOF_LONG
+# error "CURL_SIZEOF_LONG shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+# error "CURL_TYPEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_SOCKLEN_T
+# error "CURL_SIZEOF_CURL_SOCKLEN_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_already_defined
+#endif
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+# error "CURL_TYPEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_T
+# error "CURL_FORMAT_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_FORMAT_CURL_OFF_TU
+# error "CURL_FORMAT_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_already_defined
+#endif
+
+#ifdef CURL_FORMAT_OFF_T
+# error "CURL_FORMAT_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SIZEOF_CURL_OFF_T
+# error "CURL_SIZEOF_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_T
+# error "CURL_SUFFIX_CURL_OFF_T shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_already_defined
+#endif
+
+#ifdef CURL_SUFFIX_CURL_OFF_TU
+# error "CURL_SUFFIX_CURL_OFF_TU shall not be defined except in curlbuild.h"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_already_defined
+#endif
+
+/* ================================================================ */
+/* EXTERNAL INTERFACE SETTINGS FOR NON-CONFIGURE SYSTEMS ONLY */
+/* ================================================================ */
+
+#if defined(__DJGPP__) || defined(__GO32__)
+# if defined(__DJGPP__) && (__DJGPP__ > 1)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SALFORDC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__BORLANDC__)
+# if (__BORLANDC__ < 0x520)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__TURBOC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__WATCOMC__)
+# if defined(__386__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__POCC__)
+# if (__POCC__ < 280)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# elif defined(_MSC_VER)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__LCC__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__SYMBIAN32__)
+# if defined(__EABI__) /* Treat all ARM compilers equally */
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__CW32__)
+# pragma longlong on
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__VC32__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MWERKS__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(_WIN32_WCE)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__MINGW32__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__VMS)
+# if defined(__VAX)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T unsigned int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+#elif defined(__OS400__)
+# if defined(__ILEC400__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__MVS__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURL_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURL_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(__370__)
+# if defined(__IBMC__) || defined(__IBMCPP__)
+# if defined(_ILP32)
+# define CURL_SIZEOF_LONG 4
+# elif defined(_LP64)
+# define CURL_SIZEOF_LONG 8
+# endif
+# if defined(_LONG_LONG)
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(_LP64)
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# else
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+# endif
+
+#elif defined(TPF)
+# define CURL_SIZEOF_LONG 8
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+/* ===================================== */
+/* KEEP MSVC THE PENULTIMATE ENTRY */
+/* ===================================== */
+
+#elif defined(_MSC_VER)
+# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T __int64
+# define CURL_FORMAT_CURL_OFF_T "I64d"
+# define CURL_FORMAT_CURL_OFF_TU "I64u"
+# define CURL_FORMAT_OFF_T "%I64d"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T i64
+# define CURL_SUFFIX_CURL_OFF_TU ui64
+# else
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 4
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T int
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+
+/* ===================================== */
+/* KEEP GENERIC GCC THE LAST ENTRY */
+/* ===================================== */
+
+#elif defined(__GNUC__)
+# if defined(__ILP32__) || \
+ defined(__i386__) || defined(__ppc__) || defined(__arm__)
+# define CURL_SIZEOF_LONG 4
+# define CURL_TYPEOF_CURL_OFF_T long long
+# define CURL_FORMAT_CURL_OFF_T "lld"
+# define CURL_FORMAT_CURL_OFF_TU "llu"
+# define CURL_FORMAT_OFF_T "%lld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T LL
+# define CURL_SUFFIX_CURL_OFF_TU ULL
+# elif defined(__LP64__) || \
+ defined(__x86_64__) || defined(__ppc64__)
+# define CURL_SIZEOF_LONG 8
+# define CURL_TYPEOF_CURL_OFF_T long
+# define CURL_FORMAT_CURL_OFF_T "ld"
+# define CURL_FORMAT_CURL_OFF_TU "lu"
+# define CURL_FORMAT_OFF_T "%ld"
+# define CURL_SIZEOF_CURL_OFF_T 8
+# define CURL_SUFFIX_CURL_OFF_T L
+# define CURL_SUFFIX_CURL_OFF_TU UL
+# endif
+# define CURL_TYPEOF_CURL_SOCKLEN_T socklen_t
+# define CURL_SIZEOF_CURL_SOCKLEN_T 4
+# define CURL_PULL_SYS_TYPES_H 1
+# define CURL_PULL_SYS_SOCKET_H 1
+
+#else
+# error "Unknown non-configure build target!"
+ Error Compilation_aborted_Unknown_non_configure_build_target
+#endif
+
+/* CURL_PULL_SYS_TYPES_H is defined above when inclusion of header file */
+/* sys/types.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+
+/* CURL_PULL_SYS_SOCKET_H is defined above when inclusion of header file */
+/* sys/socket.h is required here to properly make type definitions below. */
+#ifdef CURL_PULL_SYS_SOCKET_H
+# include <sys/socket.h>
+#endif
+
+/* Data type definition of curl_socklen_t. */
+
+#ifdef CURL_TYPEOF_CURL_SOCKLEN_T
+ typedef CURL_TYPEOF_CURL_SOCKLEN_T curl_socklen_t;
+#endif
+
+/* Data type definition of curl_off_t. */
+
+#ifdef CURL_TYPEOF_CURL_OFF_T
+ typedef CURL_TYPEOF_CURL_OFF_T curl_off_t;
+#endif
+
+#endif /* __CURL_CURLBUILD_H */
diff --git a/libs/libcurl/include/curl/curlrules.h b/libs/libcurl/include/curl/curlrules.h
new file mode 100644
index 0000000000..7c2ede35b6
--- /dev/null
+++ b/libs/libcurl/include/curl/curlrules.h
@@ -0,0 +1,262 @@
+#ifndef __CURL_CURLRULES_H
+#define __CURL_CURLRULES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* COMPILE TIME SANITY CHECKS */
+/* ================================================================ */
+
+/*
+ * NOTE 1:
+ * -------
+ *
+ * All checks done in this file are intentionally placed in a public
+ * header file which is pulled by curl/curl.h when an application is
+ * being built using an already built libcurl library. Additionally
+ * this file is also included and used when building the library.
+ *
+ * If compilation fails on this file it is certainly sure that the
+ * problem is elsewhere. It could be a problem in the curlbuild.h
+ * header file, or simply that you are using different compilation
+ * settings than those used to build the library.
+ *
+ * Nothing in this file is intended to be modified or adjusted by the
+ * curl library user nor by the curl library builder.
+ *
+ * Do not deactivate any check, these are done to make sure that the
+ * library is properly built and used.
+ *
+ * You can find further help on the libcurl development mailing list:
+ * http://cool.haxx.se/mailman/listinfo/curl-library/
+ *
+ * NOTE 2
+ * ------
+ *
+ * Some of the following compile time checks are based on the fact
+ * that the dimension of a constant array can not be a negative one.
+ * In this way if the compile time verification fails, the compilation
+ * will fail issuing an error. The error description wording is compiler
+ * dependent but it will be quite similar to one of the following:
+ *
+ * "negative subscript or subscript is too large"
+ * "array must have at least one element"
+ * "-1 is an illegal array size"
+ * "size of array is negative"
+ *
+ * If you are building an application which tries to use an already
+ * built libcurl library and you are getting this kind of errors on
+ * this file, it is a clear indication that there is a mismatch between
+ * how the library was built and how you are trying to use it for your
+ * application. Your already compiled or binary library provider is the
+ * only one who can give you the details you need to properly use it.
+ */
+
+/*
+ * Verify that some macros are actually defined.
+ */
+
+#ifndef CURL_SIZEOF_LONG
+# error "CURL_SIZEOF_LONG definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_LONG_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_SOCKLEN_T
+# error "CURL_TYPEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_SOCKLEN_T
+# error "CURL_SIZEOF_CURL_SOCKLEN_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_SOCKLEN_T_is_missing
+#endif
+
+#ifndef CURL_TYPEOF_CURL_OFF_T
+# error "CURL_TYPEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_TYPEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_T
+# error "CURL_FORMAT_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_FORMAT_CURL_OFF_TU
+# error "CURL_FORMAT_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_CURL_OFF_TU_is_missing
+#endif
+
+#ifndef CURL_FORMAT_OFF_T
+# error "CURL_FORMAT_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_FORMAT_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SIZEOF_CURL_OFF_T
+# error "CURL_SIZEOF_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SIZEOF_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_T
+# error "CURL_SUFFIX_CURL_OFF_T definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_T_is_missing
+#endif
+
+#ifndef CURL_SUFFIX_CURL_OFF_TU
+# error "CURL_SUFFIX_CURL_OFF_TU definition is missing!"
+ Error Compilation_aborted_CURL_SUFFIX_CURL_OFF_TU_is_missing
+#endif
+
+/*
+ * Macros private to this header file.
+ */
+
+#define CurlchkszEQ(t, s) sizeof(t) == s ? 1 : -1
+
+#define CurlchkszGE(t1, t2) sizeof(t1) >= sizeof(t2) ? 1 : -1
+
+/*
+ * Verify that the size previously defined and expected for long
+ * is the same as the one reported by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_01__
+ [CurlchkszEQ(long, CURL_SIZEOF_LONG)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_off_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_02__
+ [CurlchkszEQ(curl_off_t, CURL_SIZEOF_CURL_OFF_T)];
+
+/*
+ * Verify at compile time that the size of curl_off_t as reported
+ * by sizeof() is greater or equal than the one reported for long
+ * for the current compilation.
+ */
+
+typedef char
+ __curl_rule_03__
+ [CurlchkszGE(curl_off_t, long)];
+
+/*
+ * Verify that the size previously defined and expected for
+ * curl_socklen_t is actually the the same as the one reported
+ * by sizeof() at compile time.
+ */
+
+typedef char
+ __curl_rule_04__
+ [CurlchkszEQ(curl_socklen_t, CURL_SIZEOF_CURL_SOCKLEN_T)];
+
+/*
+ * Verify at compile time that the size of curl_socklen_t as reported
+ * by sizeof() is greater or equal than the one reported for int for
+ * the current compilation.
+ */
+
+typedef char
+ __curl_rule_05__
+ [CurlchkszGE(curl_socklen_t, int)];
+
+/* ================================================================ */
+/* EXTERNALLY AND INTERNALLY VISIBLE DEFINITIONS */
+/* ================================================================ */
+
+/*
+ * CURL_ISOCPP and CURL_OFF_T_C definitions are done here in order to allow
+ * these to be visible and exported by the external libcurl interface API,
+ * while also making them visible to the library internals, simply including
+ * curl_setup.h, without actually needing to include curl.h internally.
+ * If some day this section would grow big enough, all this should be moved
+ * to its own header file.
+ */
+
+/*
+ * Figure out if we can use the ## preprocessor operator, which is supported
+ * by ISO/ANSI C and C++. Some compilers support it without setting __STDC__
+ * or __cplusplus so we need to carefully check for them too.
+ */
+
+#if defined(__STDC__) || defined(_MSC_VER) || defined(__cplusplus) || \
+ defined(__HP_aCC) || defined(__BORLANDC__) || defined(__LCC__) || \
+ defined(__POCC__) || defined(__SALFORDC__) || defined(__HIGHC__) || \
+ defined(__ILEC400__)
+ /* This compiler is believed to have an ISO compatible preprocessor */
+#define CURL_ISOCPP
+#else
+ /* This compiler is believed NOT to have an ISO compatible preprocessor */
+#undef CURL_ISOCPP
+#endif
+
+/*
+ * Macros for minimum-width signed and unsigned curl_off_t integer constants.
+ */
+
+#if defined(__BORLANDC__) && (__BORLANDC__ == 0x0551)
+# define __CURL_OFF_T_C_HLPR2(x) x
+# define __CURL_OFF_T_C_HLPR1(x) __CURL_OFF_T_C_HLPR2(x)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val) ## \
+ __CURL_OFF_T_C_HLPR1(CURL_SUFFIX_CURL_OFF_TU)
+#else
+# ifdef CURL_ISOCPP
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val ## Suffix
+# else
+# define __CURL_OFF_T_C_HLPR2(Val,Suffix) Val/**/Suffix
+# endif
+# define __CURL_OFF_T_C_HLPR1(Val,Suffix) __CURL_OFF_T_C_HLPR2(Val,Suffix)
+# define CURL_OFF_T_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_T)
+# define CURL_OFF_TU_C(Val) __CURL_OFF_T_C_HLPR1(Val,CURL_SUFFIX_CURL_OFF_TU)
+#endif
+
+/*
+ * Get rid of macros private to this header file.
+ */
+
+#undef CurlchkszEQ
+#undef CurlchkszGE
+
+/*
+ * Get rid of macros not intended to exist beyond this point.
+ */
+
+#undef CURL_PULL_WS2TCPIP_H
+#undef CURL_PULL_SYS_TYPES_H
+#undef CURL_PULL_SYS_SOCKET_H
+#undef CURL_PULL_SYS_POLL_H
+#undef CURL_PULL_STDINT_H
+#undef CURL_PULL_INTTYPES_H
+
+#undef CURL_TYPEOF_CURL_SOCKLEN_T
+#undef CURL_TYPEOF_CURL_OFF_T
+
+#ifdef CURL_NO_OLDIES
+#undef CURL_FORMAT_OFF_T /* not required since 7.19.0 - obsoleted in 7.20.0 */
+#endif
+
+#endif /* __CURL_CURLRULES_H */
diff --git a/libs/libcurl/include/curl/curlver.h b/libs/libcurl/include/curl/curlver.h
new file mode 100644
index 0000000000..43c681bc98
--- /dev/null
+++ b/libs/libcurl/include/curl/curlver.h
@@ -0,0 +1,69 @@
+#ifndef __CURL_CURLVER_H
+#define __CURL_CURLVER_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.
+ *
+ ***************************************************************************/
+
+/* This header file contains nothing but libcurl version info, generated by
+ a script at release-time. This was made its own header file in 7.11.2 */
+
+/* This is the global package copyright */
+#define LIBCURL_COPYRIGHT "1996 - 2013 Daniel Stenberg, <daniel@haxx.se>."
+
+/* This is the version number of the libcurl package from which this header
+ file origins: */
+#define LIBCURL_VERSION "7.33.0"
+
+/* The numeric version number is also available "in parts" by using these
+ defines: */
+#define LIBCURL_VERSION_MAJOR 7
+#define LIBCURL_VERSION_MINOR 33
+#define LIBCURL_VERSION_PATCH 0
+
+/* This is the numeric version of the libcurl version number, meant for easier
+ parsing and comparions by programs. The LIBCURL_VERSION_NUM define will
+ always follow this syntax:
+
+ 0xXXYYZZ
+
+ Where XX, YY and ZZ are the main version, release and patch numbers in
+ hexadecimal (using 8 bits each). All three numbers are always represented
+ using two digits. 1.2 would appear as "0x010200" while version 9.11.7
+ appears as "0x090b07".
+
+ This 6-digit (24 bits) hexadecimal number does not show pre-release number,
+ 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 0x072100
+
+/*
+ * This is the date and time when the full source package was created. The
+ * timestamp is not stored in git, as the timestamp is properly set in the
+ * tarballs by the maketgz script.
+ *
+ * The format of the date should follow this template:
+ *
+ * "Mon Feb 12 11:35:33 UTC 2007"
+ */
+#define LIBCURL_TIMESTAMP "Mon Oct 14 14:42:58 UTC 2013"
+
+#endif /* __CURL_CURLVER_H */
diff --git a/libs/libcurl/include/curl/easy.h b/libs/libcurl/include/curl/easy.h
new file mode 100644
index 0000000000..c1e3e76096
--- /dev/null
+++ b/libs/libcurl/include/curl/easy.h
@@ -0,0 +1,102 @@
+#ifndef __CURL_EASY_H
+#define __CURL_EASY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN CURL *curl_easy_init(void);
+CURL_EXTERN CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...);
+CURL_EXTERN CURLcode curl_easy_perform(CURL *curl);
+CURL_EXTERN void curl_easy_cleanup(CURL *curl);
+
+/*
+ * NAME curl_easy_getinfo()
+ *
+ * DESCRIPTION
+ *
+ * Request internal information from the curl session with this function. The
+ * third argument MUST be a pointer to a long, a pointer to a char * or a
+ * pointer to a double (as the documentation describes elsewhere). The data
+ * pointed to will be filled in accordingly and can be relied upon only if the
+ * function returns CURLE_OK. This function is intended to get used *AFTER* a
+ * performed transfer, all results from this function are undefined until the
+ * transfer is completed.
+ */
+CURL_EXTERN CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...);
+
+
+/*
+ * NAME curl_easy_duphandle()
+ *
+ * DESCRIPTION
+ *
+ * Creates a new curl session handle with the same options set for the handle
+ * passed in. Duplicating a handle could only be a matter of cloning data and
+ * options, internal state info and things like persistent connections cannot
+ * be transferred. It is useful in multithreaded applications when you can run
+ * curl_easy_duphandle() for each new thread to avoid a series of identical
+ * curl_easy_setopt() invokes in every thread.
+ */
+CURL_EXTERN CURL* curl_easy_duphandle(CURL *curl);
+
+/*
+ * NAME curl_easy_reset()
+ *
+ * DESCRIPTION
+ *
+ * Re-initializes a CURL handle to the default values. This puts back the
+ * handle to the same state as it was in when it was just created.
+ *
+ * It does keep: live connections, the Session ID cache, the DNS cache and the
+ * cookies.
+ */
+CURL_EXTERN void curl_easy_reset(CURL *curl);
+
+/*
+ * NAME curl_easy_recv()
+ *
+ * DESCRIPTION
+ *
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen,
+ size_t *n);
+
+/*
+ * NAME curl_easy_send()
+ *
+ * DESCRIPTION
+ *
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURL_EXTERN CURLcode curl_easy_send(CURL *curl, const void *buffer,
+ size_t buflen, size_t *n);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/libs/libcurl/include/curl/mprintf.h b/libs/libcurl/include/curl/mprintf.h
new file mode 100644
index 0000000000..cc9e7f5d1f
--- /dev/null
+++ b/libs/libcurl/include/curl/mprintf.h
@@ -0,0 +1,81 @@
+#ifndef __CURL_MPRINTF_H
+#define __CURL_MPRINTF_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 <stdarg.h>
+#include <stdio.h> /* needed for FILE */
+
+#include "curl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+CURL_EXTERN int curl_mprintf(const char *format, ...);
+CURL_EXTERN int curl_mfprintf(FILE *fd, const char *format, ...);
+CURL_EXTERN int curl_msprintf(char *buffer, const char *format, ...);
+CURL_EXTERN int curl_msnprintf(char *buffer, size_t maxlength,
+ const char *format, ...);
+CURL_EXTERN int curl_mvprintf(const char *format, va_list args);
+CURL_EXTERN int curl_mvfprintf(FILE *fd, const char *format, va_list args);
+CURL_EXTERN int curl_mvsprintf(char *buffer, const char *format, va_list args);
+CURL_EXTERN int curl_mvsnprintf(char *buffer, size_t maxlength,
+ const char *format, va_list args);
+CURL_EXTERN char *curl_maprintf(const char *format, ...);
+CURL_EXTERN char *curl_mvaprintf(const char *format, va_list args);
+
+#ifdef _MPRINTF_REPLACE
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef vsprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+# define printf curl_mprintf
+# define fprintf curl_mfprintf
+#ifdef CURLDEBUG
+/* When built with CURLDEBUG we define away the sprintf functions since we
+ don't want internal code to be using them */
+# define sprintf sprintf_was_used
+# define vsprintf vsprintf_was_used
+#else
+# define sprintf curl_msprintf
+# define vsprintf curl_mvsprintf
+#endif
+# define snprintf curl_msnprintf
+# define vprintf curl_mvprintf
+# define vfprintf curl_mvfprintf
+# define vsnprintf curl_mvsnprintf
+# define aprintf curl_maprintf
+# define vaprintf curl_mvaprintf
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __CURL_MPRINTF_H */
diff --git a/libs/libcurl/include/curl/multi.h b/libs/libcurl/include/curl/multi.h
new file mode 100644
index 0000000000..3c4acb0f6e
--- /dev/null
+++ b/libs/libcurl/include/curl/multi.h
@@ -0,0 +1,399 @@
+#ifndef __CURL_MULTI_H
+#define __CURL_MULTI_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.
+ *
+ ***************************************************************************/
+/*
+ This is an "external" header file. Don't give away any internals here!
+
+ GOALS
+
+ o Enable a "pull" interface. The application that uses libcurl decides where
+ and when to ask libcurl to get/send data.
+
+ o Enable multiple simultaneous transfers in the same thread without making it
+ complicated for the application.
+
+ o Enable the application to select() on its own file descriptors and curl's
+ file descriptors simultaneous easily.
+
+*/
+
+/*
+ * This header file should not really need to include "curl.h" since curl.h
+ * itself includes this file and we expect user applications to do #include
+ * <curl/curl.h> without the need for especially including multi.h.
+ *
+ * For some reason we added this include here at one point, and rather than to
+ * break existing (wrongly written) libcurl applications, we leave it as-is
+ * but with this warning attached.
+ */
+#include "curl.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef void CURLM;
+
+typedef enum {
+ CURLM_CALL_MULTI_PERFORM = -1, /* please call curl_multi_perform() or
+ curl_multi_socket*() soon */
+ CURLM_OK,
+ CURLM_BAD_HANDLE, /* the passed-in handle is not a valid CURLM handle */
+ CURLM_BAD_EASY_HANDLE, /* an easy handle was not good/valid */
+ CURLM_OUT_OF_MEMORY, /* if you ever get this, you're in deep sh*t */
+ 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;
+
+/* just to make code nicer when using curl_multi_socket() you can now check
+ for CURLM_CALL_MULTI_SOCKET too in the same style it works for
+ curl_multi_perform() and CURLM_CALL_MULTI_PERFORM */
+#define CURLM_CALL_MULTI_SOCKET CURLM_CALL_MULTI_PERFORM
+
+typedef enum {
+ CURLMSG_NONE, /* first, not used */
+ CURLMSG_DONE, /* This easy handle has completed. 'result' contains
+ the CURLcode of the transfer */
+ CURLMSG_LAST /* last, not used */
+} CURLMSG;
+
+struct CURLMsg {
+ CURLMSG msg; /* what this message means */
+ CURL *easy_handle; /* the handle it concerns */
+ union {
+ void *whatever; /* message-specific data */
+ CURLcode result; /* return code for transfer */
+ } data;
+};
+typedef struct CURLMsg CURLMsg;
+
+/* Based on poll(2) structure and values.
+ * We don't use pollfd and POLL* constants explicitly
+ * to cover platforms without poll(). */
+#define CURL_WAIT_POLLIN 0x0001
+#define CURL_WAIT_POLLPRI 0x0002
+#define CURL_WAIT_POLLOUT 0x0004
+
+struct curl_waitfd {
+ curl_socket_t fd;
+ short events;
+ short revents; /* not supported yet */
+};
+
+/*
+ * Name: curl_multi_init()
+ *
+ * Desc: inititalize multi-style curl usage
+ *
+ * Returns: a new CURLM handle to use in all 'curl_multi' functions.
+ */
+CURL_EXTERN CURLM *curl_multi_init(void);
+
+/*
+ * Name: curl_multi_add_handle()
+ *
+ * Desc: add a standard curl handle to the multi stack
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_remove_handle()
+ *
+ * Desc: removes a curl handle from the multi stack again
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+ CURL *curl_handle);
+
+ /*
+ * Name: curl_multi_fdset()
+ *
+ * Desc: Ask curl for its fd_set sets. The app can use these to select() or
+ * poll() on. We want curl_multi_perform() called as soon as one of
+ * them are ready.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_fdset(CURLM *multi_handle,
+ fd_set *read_fd_set,
+ fd_set *write_fd_set,
+ fd_set *exc_fd_set,
+ int *max_fd);
+
+/*
+ * Name: curl_multi_wait()
+ *
+ * Desc: Poll on all fds within a CURLM set as well as any
+ * additional fds passed to the function.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_wait(CURLM *multi_handle,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret);
+
+ /*
+ * Name: curl_multi_perform()
+ *
+ * Desc: When the app thinks there's data available for curl it calls this
+ * function to read/write whatever there is right now. This returns
+ * as soon as the reads and writes are done. This function does not
+ * require that there actually is data available for reading or that
+ * data can be written, it can be called just in case. It returns
+ * the number of handles that still transfer data in the second
+ * argument's integer-pointer.
+ *
+ * Returns: CURLMcode type, general multi error code. *NOTE* that this only
+ * returns errors etc regarding the whole multi stack. There might
+ * still have occurred problems on invidual transfers even when this
+ * returns OK.
+ */
+CURL_EXTERN CURLMcode curl_multi_perform(CURLM *multi_handle,
+ int *running_handles);
+
+ /*
+ * Name: curl_multi_cleanup()
+ *
+ * Desc: Cleans up and removes a whole multi stack. It does not free or
+ * touch any individual easy handles in any way. We need to define
+ * in what state those handles will be if this function is called
+ * in the middle of a transfer.
+ *
+ * Returns: CURLMcode type, general multi error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_cleanup(CURLM *multi_handle);
+
+/*
+ * Name: curl_multi_info_read()
+ *
+ * Desc: Ask the multi handle if there's any messages/informationals from
+ * the individual transfers. Messages include informationals such as
+ * error code from the transfer or just the fact that a transfer is
+ * completed. More details on these should be written down as well.
+ *
+ * Repeated calls to this function will return a new struct each
+ * time, until a special "end of msgs" struct is returned as a signal
+ * that there is no more to get at this point.
+ *
+ * The data the returned pointer points to will not survive calling
+ * curl_multi_cleanup().
+ *
+ * The 'CURLMsg' struct is meant to be very simple and only contain
+ * very basic informations. If more involved information is wanted,
+ * we will provide the particular "transfer handle" in that struct
+ * and that should/could/would be used in subsequent
+ * curl_easy_getinfo() calls (or similar). The point being that we
+ * must never expose complex structs to applications, as then we'll
+ * undoubtably get backwards compatibility problems in the future.
+ *
+ * Returns: A pointer to a filled-in struct, or NULL if it failed or ran out
+ * of structs. It also writes the number of messages left in the
+ * queue (after this read) in the integer the second argument points
+ * to.
+ */
+CURL_EXTERN CURLMsg *curl_multi_info_read(CURLM *multi_handle,
+ int *msgs_in_queue);
+
+/*
+ * Name: curl_multi_strerror()
+ *
+ * Desc: The curl_multi_strerror function may be used to turn a CURLMcode
+ * value into the equivalent human readable error string. This is
+ * useful for printing meaningful error messages.
+ *
+ * Returns: A pointer to a zero-terminated error message.
+ */
+CURL_EXTERN const char *curl_multi_strerror(CURLMcode);
+
+/*
+ * Name: curl_multi_socket() and
+ * curl_multi_socket_all()
+ *
+ * Desc: An alternative version of curl_multi_perform() that allows the
+ * application to pass in one of the file descriptors that have been
+ * detected to have "action" on them and let libcurl perform.
+ * See man page for details.
+ */
+#define CURL_POLL_NONE 0
+#define CURL_POLL_IN 1
+#define CURL_POLL_OUT 2
+#define CURL_POLL_INOUT 3
+#define CURL_POLL_REMOVE 4
+
+#define CURL_SOCKET_TIMEOUT CURL_SOCKET_BAD
+
+#define CURL_CSELECT_IN 0x01
+#define CURL_CSELECT_OUT 0x02
+#define CURL_CSELECT_ERR 0x04
+
+typedef int (*curl_socket_callback)(CURL *easy, /* easy handle */
+ curl_socket_t s, /* socket */
+ int what, /* see above */
+ void *userp, /* private callback
+ pointer */
+ void *socketp); /* private socket
+ pointer */
+/*
+ * Name: curl_multi_timer_callback
+ *
+ * Desc: Called by libcurl whenever the library detects a change in the
+ * maximum number of milliseconds the app is allowed to wait before
+ * curl_multi_socket() or curl_multi_perform() must be called
+ * (to allow libcurl's timed events to take place).
+ *
+ * Returns: The callback should return zero.
+ */
+typedef int (*curl_multi_timer_callback)(CURLM *multi, /* multi handle */
+ long timeout_ms, /* see above */
+ void *userp); /* private callback
+ pointer */
+
+CURL_EXTERN CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_action(CURLM *multi_handle,
+ curl_socket_t s,
+ int ev_bitmask,
+ int *running_handles);
+
+CURL_EXTERN CURLMcode curl_multi_socket_all(CURLM *multi_handle,
+ int *running_handles);
+
+#ifndef CURL_ALLOW_OLD_MULTI_SOCKET
+/* This macro below was added in 7.16.3 to push users who recompile to use
+ the new curl_multi_socket_action() instead of the old curl_multi_socket()
+*/
+#define curl_multi_socket(x,y,z) curl_multi_socket_action(x,y,0,z)
+#endif
+
+/*
+ * Name: curl_multi_timeout()
+ *
+ * Desc: Returns the maximum number of milliseconds the app is allowed to
+ * wait before curl_multi_socket() or curl_multi_perform() must be
+ * called (to allow libcurl's timed events to take place).
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_timeout(CURLM *multi_handle,
+ long *milliseconds);
+
+#undef CINIT /* re-using the same name as in curl.h */
+
+#ifdef CURL_ISOCPP
+#define CINIT(name,type,num) CURLMOPT_ ## name = CURLOPTTYPE_ ## type + num
+#else
+/* The macro "##" is ISO C, we assume pre-ISO C doesn't support it. */
+#define LONG CURLOPTTYPE_LONG
+#define OBJECTPOINT CURLOPTTYPE_OBJECTPOINT
+#define FUNCTIONPOINT CURLOPTTYPE_FUNCTIONPOINT
+#define OFF_T CURLOPTTYPE_OFF_T
+#define CINIT(name,type,number) CURLMOPT_/**/name = type + number
+#endif
+
+typedef enum {
+ /* This is the socket callback function pointer */
+ CINIT(SOCKETFUNCTION, FUNCTIONPOINT, 1),
+
+ /* This is the argument passed to the socket callback */
+ CINIT(SOCKETDATA, OBJECTPOINT, 2),
+
+ /* set to 1 to enable pipelining for this multi handle */
+ CINIT(PIPELINING, LONG, 3),
+
+ /* This is the timer callback function pointer */
+ CINIT(TIMERFUNCTION, FUNCTIONPOINT, 4),
+
+ /* This is the argument passed to the timer callback */
+ CINIT(TIMERDATA, OBJECTPOINT, 5),
+
+ /* maximum number of entries in the connection cache */
+ CINIT(MAXCONNECTS, LONG, 6),
+
+ /* maximum number of (pipelining) connections to one host */
+ CINIT(MAX_HOST_CONNECTIONS, LONG, 7),
+
+ /* maximum number of requests in a pipeline */
+ CINIT(MAX_PIPELINE_LENGTH, LONG, 8),
+
+ /* a connection with a content-length longer than this
+ will not be considered for pipelining */
+ CINIT(CONTENT_LENGTH_PENALTY_SIZE, OFF_T, 9),
+
+ /* a connection with a chunk length longer than this
+ will not be considered for pipelining */
+ CINIT(CHUNK_LENGTH_PENALTY_SIZE, OFF_T, 10),
+
+ /* a list of site names(+port) that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SITE_BL, OBJECTPOINT, 11),
+
+ /* a list of server types that are blacklisted from
+ pipelining */
+ CINIT(PIPELINING_SERVER_BL, OBJECTPOINT, 12),
+
+ /* maximum number of open connections in total */
+ CINIT(MAX_TOTAL_CONNECTIONS, LONG, 13),
+
+ CURLMOPT_LASTENTRY /* the last unused */
+} CURLMoption;
+
+
+/*
+ * Name: curl_multi_setopt()
+ *
+ * Desc: Sets options for the multi handle.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_setopt(CURLM *multi_handle,
+ CURLMoption option, ...);
+
+
+/*
+ * Name: curl_multi_assign()
+ *
+ * Desc: This function sets an association in the multi handle between the
+ * given socket and a private pointer of the application. This is
+ * (only) useful for curl_multi_socket uses.
+ *
+ * Returns: CURLM error code.
+ */
+CURL_EXTERN CURLMcode curl_multi_assign(CURLM *multi_handle,
+ curl_socket_t sockfd, void *sockp);
+
+#ifdef __cplusplus
+} /* end of extern "C" */
+#endif
+
+#endif
diff --git a/libs/libcurl/include/curl/stdcheaders.h b/libs/libcurl/include/curl/stdcheaders.h
new file mode 100644
index 0000000000..ad82ef6335
--- /dev/null
+++ b/libs/libcurl/include/curl/stdcheaders.h
@@ -0,0 +1,33 @@
+#ifndef __STDC_HEADERS_H
+#define __STDC_HEADERS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <sys/types.h>
+
+size_t fread (void *, size_t, size_t, FILE *);
+size_t fwrite (const void *, size_t, size_t, FILE *);
+
+int strcasecmp(const char *, const char *);
+int strncasecmp(const char *, const char *, size_t);
+
+#endif /* __STDC_HEADERS_H */
diff --git a/libs/libcurl/include/curl/typecheck-gcc.h b/libs/libcurl/include/curl/typecheck-gcc.h
new file mode 100644
index 0000000000..e8f1dff9ab
--- /dev/null
+++ b/libs/libcurl/include/curl/typecheck-gcc.h
@@ -0,0 +1,609 @@
+#ifndef __CURL_TYPECHECK_GCC_H
+#define __CURL_TYPECHECK_GCC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* wraps curl_easy_setopt() with typechecking */
+
+/* To add a new kind of warning, add an
+ * if(_curl_is_sometype_option(_curl_opt))
+ * if(!_curl_is_sometype(value))
+ * _curl_easy_setopt_err_sometype();
+ * block and define _curl_is_sometype_option, _curl_is_sometype and
+ * _curl_easy_setopt_err_sometype below
+ *
+ * NOTE: We use two nested 'if' statements here instead of the && operator, in
+ * order to work around gcc bug #32061. It affects only gcc 4.3.x/4.4.x
+ * when compiling with -Wlogical-op.
+ *
+ * To add an option that uses the same type as an existing option, you'll just
+ * need to extend the appropriate _curl_*_option macro
+ */
+#define curl_easy_setopt(handle, option, value) \
+__extension__ ({ \
+ __typeof__ (option) _curl_opt = option; \
+ if(__builtin_constant_p(_curl_opt)) { \
+ if(_curl_is_long_option(_curl_opt)) \
+ if(!_curl_is_long(value)) \
+ _curl_easy_setopt_err_long(); \
+ if(_curl_is_off_t_option(_curl_opt)) \
+ if(!_curl_is_off_t(value)) \
+ _curl_easy_setopt_err_curl_off_t(); \
+ if(_curl_is_string_option(_curl_opt)) \
+ if(!_curl_is_string(value)) \
+ _curl_easy_setopt_err_string(); \
+ if(_curl_is_write_cb_option(_curl_opt)) \
+ if(!_curl_is_write_cb(value)) \
+ _curl_easy_setopt_err_write_callback(); \
+ if((_curl_opt) == CURLOPT_READFUNCTION) \
+ if(!_curl_is_read_cb(value)) \
+ _curl_easy_setopt_err_read_cb(); \
+ if((_curl_opt) == CURLOPT_IOCTLFUNCTION) \
+ if(!_curl_is_ioctl_cb(value)) \
+ _curl_easy_setopt_err_ioctl_cb(); \
+ if((_curl_opt) == CURLOPT_SOCKOPTFUNCTION) \
+ if(!_curl_is_sockopt_cb(value)) \
+ _curl_easy_setopt_err_sockopt_cb(); \
+ if((_curl_opt) == CURLOPT_OPENSOCKETFUNCTION) \
+ if(!_curl_is_opensocket_cb(value)) \
+ _curl_easy_setopt_err_opensocket_cb(); \
+ if((_curl_opt) == CURLOPT_PROGRESSFUNCTION) \
+ if(!_curl_is_progress_cb(value)) \
+ _curl_easy_setopt_err_progress_cb(); \
+ if((_curl_opt) == CURLOPT_DEBUGFUNCTION) \
+ if(!_curl_is_debug_cb(value)) \
+ _curl_easy_setopt_err_debug_cb(); \
+ if((_curl_opt) == CURLOPT_SSL_CTX_FUNCTION) \
+ if(!_curl_is_ssl_ctx_cb(value)) \
+ _curl_easy_setopt_err_ssl_ctx_cb(); \
+ if(_curl_is_conv_cb_option(_curl_opt)) \
+ if(!_curl_is_conv_cb(value)) \
+ _curl_easy_setopt_err_conv_cb(); \
+ if((_curl_opt) == CURLOPT_SEEKFUNCTION) \
+ if(!_curl_is_seek_cb(value)) \
+ _curl_easy_setopt_err_seek_cb(); \
+ if(_curl_is_cb_data_option(_curl_opt)) \
+ if(!_curl_is_cb_data(value)) \
+ _curl_easy_setopt_err_cb_data(); \
+ if((_curl_opt) == CURLOPT_ERRORBUFFER) \
+ if(!_curl_is_error_buffer(value)) \
+ _curl_easy_setopt_err_error_buffer(); \
+ if((_curl_opt) == CURLOPT_STDERR) \
+ if(!_curl_is_FILE(value)) \
+ _curl_easy_setopt_err_FILE(); \
+ if(_curl_is_postfields_option(_curl_opt)) \
+ if(!_curl_is_postfields(value)) \
+ _curl_easy_setopt_err_postfields(); \
+ if((_curl_opt) == CURLOPT_HTTPPOST) \
+ if(!_curl_is_arr((value), struct curl_httppost)) \
+ _curl_easy_setopt_err_curl_httpost(); \
+ if(_curl_is_slist_option(_curl_opt)) \
+ if(!_curl_is_arr((value), struct curl_slist)) \
+ _curl_easy_setopt_err_curl_slist(); \
+ if((_curl_opt) == CURLOPT_SHARE) \
+ if(!_curl_is_ptr((value), CURLSH)) \
+ _curl_easy_setopt_err_CURLSH(); \
+ } \
+ curl_easy_setopt(handle, _curl_opt, value); \
+})
+
+/* wraps curl_easy_getinfo() with typechecking */
+/* FIXME: don't allow const pointers */
+#define curl_easy_getinfo(handle, info, arg) \
+__extension__ ({ \
+ __typeof__ (info) _curl_info = info; \
+ if(__builtin_constant_p(_curl_info)) { \
+ if(_curl_is_string_info(_curl_info)) \
+ if(!_curl_is_arr((arg), char *)) \
+ _curl_easy_getinfo_err_string(); \
+ if(_curl_is_long_info(_curl_info)) \
+ if(!_curl_is_arr((arg), long)) \
+ _curl_easy_getinfo_err_long(); \
+ if(_curl_is_double_info(_curl_info)) \
+ if(!_curl_is_arr((arg), double)) \
+ _curl_easy_getinfo_err_double(); \
+ if(_curl_is_slist_info(_curl_info)) \
+ if(!_curl_is_arr((arg), struct curl_slist *)) \
+ _curl_easy_getinfo_err_curl_slist(); \
+ } \
+ curl_easy_getinfo(handle, _curl_info, arg); \
+})
+
+/* TODO: typechecking for curl_share_setopt() and curl_multi_setopt(),
+ * for now just make sure that the functions are called with three
+ * arguments
+ */
+#define curl_share_setopt(share,opt,param) curl_share_setopt(share,opt,param)
+#define curl_multi_setopt(handle,opt,param) curl_multi_setopt(handle,opt,param)
+
+
+/* the actual warnings, triggered by calling the _curl_easy_setopt_err*
+ * functions */
+
+/* To define a new warning, use _CURL_WARNING(identifier, "message") */
+#define _CURL_WARNING(id, message) \
+ static void __attribute__((__warning__(message))) \
+ __attribute__((__unused__)) __attribute__((__noinline__)) \
+ id(void) { __asm__(""); }
+
+_CURL_WARNING(_curl_easy_setopt_err_long,
+ "curl_easy_setopt expects a long argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_off_t,
+ "curl_easy_setopt expects a curl_off_t argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_string,
+ "curl_easy_setopt expects a "
+ "string (char* or char[]) argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_write_callback,
+ "curl_easy_setopt expects a curl_write_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_read_cb,
+ "curl_easy_setopt expects a curl_read_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ioctl_cb,
+ "curl_easy_setopt expects a curl_ioctl_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_sockopt_cb,
+ "curl_easy_setopt expects a curl_sockopt_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_opensocket_cb,
+ "curl_easy_setopt expects a "
+ "curl_opensocket_callback argument for this option"
+ )
+_CURL_WARNING(_curl_easy_setopt_err_progress_cb,
+ "curl_easy_setopt expects a curl_progress_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_debug_cb,
+ "curl_easy_setopt expects a curl_debug_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_ssl_ctx_cb,
+ "curl_easy_setopt expects a curl_ssl_ctx_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_conv_cb,
+ "curl_easy_setopt expects a curl_conv_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_seek_cb,
+ "curl_easy_setopt expects a curl_seek_callback argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_cb_data,
+ "curl_easy_setopt expects a "
+ "private data pointer as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_error_buffer,
+ "curl_easy_setopt expects a "
+ "char buffer of CURL_ERROR_SIZE as argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_FILE,
+ "curl_easy_setopt expects a FILE* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_postfields,
+ "curl_easy_setopt expects a void* or char* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_httpost,
+ "curl_easy_setopt expects a struct curl_httppost* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_curl_slist,
+ "curl_easy_setopt expects a struct curl_slist* argument for this option")
+_CURL_WARNING(_curl_easy_setopt_err_CURLSH,
+ "curl_easy_setopt expects a CURLSH* argument for this option")
+
+_CURL_WARNING(_curl_easy_getinfo_err_string,
+ "curl_easy_getinfo expects a pointer to char * for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_long,
+ "curl_easy_getinfo expects a pointer to long for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_double,
+ "curl_easy_getinfo expects a pointer to double for this info")
+_CURL_WARNING(_curl_easy_getinfo_err_curl_slist,
+ "curl_easy_getinfo expects a pointer to struct curl_slist * for this info")
+
+/* groups of curl_easy_setops options that take the same type of argument */
+
+/* To add a new option to one of the groups, just add
+ * (option) == CURLOPT_SOMETHING
+ * to the or-expression. If the option takes a long or curl_off_t, you don't
+ * have to do anything
+ */
+
+/* evaluates to true if option takes a long argument */
+#define _curl_is_long_option(option) \
+ (0 < (option) && (option) < CURLOPTTYPE_OBJECTPOINT)
+
+#define _curl_is_off_t_option(option) \
+ ((option) > CURLOPTTYPE_OFF_T)
+
+/* evaluates to true if option takes a char* argument */
+#define _curl_is_string_option(option) \
+ ((option) == CURLOPT_URL || \
+ (option) == CURLOPT_PROXY || \
+ (option) == CURLOPT_INTERFACE || \
+ (option) == CURLOPT_NETRC_FILE || \
+ (option) == CURLOPT_USERPWD || \
+ (option) == CURLOPT_USERNAME || \
+ (option) == CURLOPT_PASSWORD || \
+ (option) == CURLOPT_PROXYUSERPWD || \
+ (option) == CURLOPT_PROXYUSERNAME || \
+ (option) == CURLOPT_PROXYPASSWORD || \
+ (option) == CURLOPT_NOPROXY || \
+ (option) == CURLOPT_ACCEPT_ENCODING || \
+ (option) == CURLOPT_REFERER || \
+ (option) == CURLOPT_USERAGENT || \
+ (option) == CURLOPT_COOKIE || \
+ (option) == CURLOPT_COOKIEFILE || \
+ (option) == CURLOPT_COOKIEJAR || \
+ (option) == CURLOPT_COOKIELIST || \
+ (option) == CURLOPT_FTPPORT || \
+ (option) == CURLOPT_FTP_ALTERNATIVE_TO_USER || \
+ (option) == CURLOPT_FTP_ACCOUNT || \
+ (option) == CURLOPT_RANGE || \
+ (option) == CURLOPT_CUSTOMREQUEST || \
+ (option) == CURLOPT_SSLCERT || \
+ (option) == CURLOPT_SSLCERTTYPE || \
+ (option) == CURLOPT_SSLKEY || \
+ (option) == CURLOPT_SSLKEYTYPE || \
+ (option) == CURLOPT_KEYPASSWD || \
+ (option) == CURLOPT_SSLENGINE || \
+ (option) == CURLOPT_CAINFO || \
+ (option) == CURLOPT_CAPATH || \
+ (option) == CURLOPT_RANDOM_FILE || \
+ (option) == CURLOPT_EGDSOCKET || \
+ (option) == CURLOPT_SSL_CIPHER_LIST || \
+ (option) == CURLOPT_KRBLEVEL || \
+ (option) == CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 || \
+ (option) == CURLOPT_SSH_PUBLIC_KEYFILE || \
+ (option) == CURLOPT_SSH_PRIVATE_KEYFILE || \
+ (option) == CURLOPT_CRLFILE || \
+ (option) == CURLOPT_ISSUERCERT || \
+ (option) == CURLOPT_SOCKS5_GSSAPI_SERVICE || \
+ (option) == CURLOPT_SSH_KNOWNHOSTS || \
+ (option) == CURLOPT_MAIL_FROM || \
+ (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 */
+#define _curl_is_write_cb_option(option) \
+ ((option) == CURLOPT_HEADERFUNCTION || \
+ (option) == CURLOPT_WRITEFUNCTION)
+
+/* evaluates to true if option takes a curl_conv_callback argument */
+#define _curl_is_conv_cb_option(option) \
+ ((option) == CURLOPT_CONV_TO_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_NETWORK_FUNCTION || \
+ (option) == CURLOPT_CONV_FROM_UTF8_FUNCTION)
+
+/* evaluates to true if option takes a data argument to pass to a callback */
+#define _curl_is_cb_data_option(option) \
+ ((option) == CURLOPT_WRITEDATA || \
+ (option) == CURLOPT_READDATA || \
+ (option) == CURLOPT_IOCTLDATA || \
+ (option) == CURLOPT_SOCKOPTDATA || \
+ (option) == CURLOPT_OPENSOCKETDATA || \
+ (option) == CURLOPT_PROGRESSDATA || \
+ (option) == CURLOPT_WRITEHEADER || \
+ (option) == CURLOPT_DEBUGDATA || \
+ (option) == CURLOPT_SSL_CTX_DATA || \
+ (option) == CURLOPT_SEEKDATA || \
+ (option) == CURLOPT_PRIVATE || \
+ (option) == CURLOPT_SSH_KEYDATA || \
+ (option) == CURLOPT_INTERLEAVEDATA || \
+ (option) == CURLOPT_CHUNK_DATA || \
+ (option) == CURLOPT_FNMATCH_DATA || \
+ 0)
+
+/* evaluates to true if option takes a POST data argument (void* or char*) */
+#define _curl_is_postfields_option(option) \
+ ((option) == CURLOPT_POSTFIELDS || \
+ (option) == CURLOPT_COPYPOSTFIELDS || \
+ 0)
+
+/* evaluates to true if option takes a struct curl_slist * argument */
+#define _curl_is_slist_option(option) \
+ ((option) == CURLOPT_HTTPHEADER || \
+ (option) == CURLOPT_HTTP200ALIASES || \
+ (option) == CURLOPT_QUOTE || \
+ (option) == CURLOPT_POSTQUOTE || \
+ (option) == CURLOPT_PREQUOTE || \
+ (option) == CURLOPT_TELNETOPTIONS || \
+ (option) == CURLOPT_MAIL_RCPT || \
+ 0)
+
+/* groups of curl_easy_getinfo infos that take the same type of argument */
+
+/* evaluates to true if info expects a pointer to char * argument */
+#define _curl_is_string_info(info) \
+ (CURLINFO_STRING < (info) && (info) < CURLINFO_LONG)
+
+/* evaluates to true if info expects a pointer to long argument */
+#define _curl_is_long_info(info) \
+ (CURLINFO_LONG < (info) && (info) < CURLINFO_DOUBLE)
+
+/* evaluates to true if info expects a pointer to double argument */
+#define _curl_is_double_info(info) \
+ (CURLINFO_DOUBLE < (info) && (info) < CURLINFO_SLIST)
+
+/* true if info expects a pointer to struct curl_slist * argument */
+#define _curl_is_slist_info(info) \
+ (CURLINFO_SLIST < (info))
+
+
+/* typecheck helpers -- check whether given expression has requested type*/
+
+/* For pointers, you can use the _curl_is_ptr/_curl_is_arr macros,
+ * otherwise define a new macro. Search for __builtin_types_compatible_p
+ * in the GCC manual.
+ * NOTE: these macros MUST NOT EVALUATE their arguments! The argument is
+ * the actual expression passed to the curl_easy_setopt macro. This
+ * means that you can only apply the sizeof and __typeof__ operators, no
+ * == or whatsoever.
+ */
+
+/* XXX: should evaluate to true iff expr is a pointer */
+#define _curl_is_any_ptr(expr) \
+ (sizeof(expr) == sizeof(void*))
+
+/* evaluates to true if expr is NULL */
+/* XXX: must not evaluate expr, so this check is not accurate */
+#define _curl_is_NULL(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), __typeof__(NULL)))
+
+/* evaluates to true if expr is type*, const type* or NULL */
+#define _curl_is_ptr(expr, type) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), type *) || \
+ __builtin_types_compatible_p(__typeof__(expr), const type *))
+
+/* evaluates to true if expr is one of type[], type*, NULL or const type* */
+#define _curl_is_arr(expr, type) \
+ (_curl_is_ptr((expr), type) || \
+ __builtin_types_compatible_p(__typeof__(expr), type []))
+
+/* evaluates to true if expr is a string */
+#define _curl_is_string(expr) \
+ (_curl_is_arr((expr), char) || \
+ _curl_is_arr((expr), signed char) || \
+ _curl_is_arr((expr), unsigned char))
+
+/* evaluates to true if expr is a long (no matter the signedness)
+ * XXX: for now, int is also accepted (and therefore short and char, which
+ * are promoted to int when passed to a variadic function) */
+#define _curl_is_long(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), long) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed long) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned long) || \
+ __builtin_types_compatible_p(__typeof__(expr), int) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed int) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned int) || \
+ __builtin_types_compatible_p(__typeof__(expr), short) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed short) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned short) || \
+ __builtin_types_compatible_p(__typeof__(expr), char) || \
+ __builtin_types_compatible_p(__typeof__(expr), signed char) || \
+ __builtin_types_compatible_p(__typeof__(expr), unsigned char))
+
+/* evaluates to true if expr is of type curl_off_t */
+#define _curl_is_off_t(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), curl_off_t))
+
+/* evaluates to true if expr is abuffer suitable for CURLOPT_ERRORBUFFER */
+/* XXX: also check size of an char[] array? */
+#define _curl_is_error_buffer(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), char *) || \
+ __builtin_types_compatible_p(__typeof__(expr), char[]))
+
+/* evaluates to true if expr is of type (const) void* or (const) FILE* */
+#if 0
+#define _curl_is_cb_data(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_ptr((expr), FILE))
+#else /* be less strict */
+#define _curl_is_cb_data(expr) \
+ _curl_is_any_ptr(expr)
+#endif
+
+/* evaluates to true if expr is of type FILE* */
+#define _curl_is_FILE(expr) \
+ (__builtin_types_compatible_p(__typeof__(expr), FILE *))
+
+/* evaluates to true if expr can be passed as POST data (void* or char*) */
+#define _curl_is_postfields(expr) \
+ (_curl_is_ptr((expr), void) || \
+ _curl_is_arr((expr), char))
+
+/* FIXME: the whole callback checking is messy...
+ * The idea is to tolerate char vs. void and const vs. not const
+ * pointers in arguments at least
+ */
+/* helper: __builtin_types_compatible_p distinguishes between functions and
+ * function pointers, hide it */
+#define _curl_callback_compatible(func, type) \
+ (__builtin_types_compatible_p(__typeof__(func), type) || \
+ __builtin_types_compatible_p(__typeof__(func), type*))
+
+/* evaluates to true if expr is of type curl_read_callback or "similar" */
+#define _curl_is_read_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), __typeof__(fread)) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_read_callback) || \
+ _curl_callback_compatible((expr), _curl_read_callback1) || \
+ _curl_callback_compatible((expr), _curl_read_callback2) || \
+ _curl_callback_compatible((expr), _curl_read_callback3) || \
+ _curl_callback_compatible((expr), _curl_read_callback4) || \
+ _curl_callback_compatible((expr), _curl_read_callback5) || \
+ _curl_callback_compatible((expr), _curl_read_callback6))
+typedef size_t (_curl_read_callback1)(char *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback2)(char *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback3)(char *, size_t, size_t, FILE*);
+typedef size_t (_curl_read_callback4)(void *, size_t, size_t, void*);
+typedef size_t (_curl_read_callback5)(void *, size_t, size_t, const void*);
+typedef size_t (_curl_read_callback6)(void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_write_callback or "similar" */
+#define _curl_is_write_cb(expr) \
+ (_curl_is_read_cb(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), __typeof__(fwrite)) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_write_callback) || \
+ _curl_callback_compatible((expr), _curl_write_callback1) || \
+ _curl_callback_compatible((expr), _curl_write_callback2) || \
+ _curl_callback_compatible((expr), _curl_write_callback3) || \
+ _curl_callback_compatible((expr), _curl_write_callback4) || \
+ _curl_callback_compatible((expr), _curl_write_callback5) || \
+ _curl_callback_compatible((expr), _curl_write_callback6))
+typedef size_t (_curl_write_callback1)(const char *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback2)(const char *, size_t, size_t,
+ const void*);
+typedef size_t (_curl_write_callback3)(const char *, size_t, size_t, FILE*);
+typedef size_t (_curl_write_callback4)(const void *, size_t, size_t, void*);
+typedef size_t (_curl_write_callback5)(const void *, size_t, size_t,
+ const void*);
+typedef size_t (_curl_write_callback6)(const void *, size_t, size_t, FILE*);
+
+/* evaluates to true if expr is of type curl_ioctl_callback or "similar" */
+#define _curl_is_ioctl_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_ioctl_callback) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback1) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback2) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback3) || \
+ _curl_callback_compatible((expr), _curl_ioctl_callback4))
+typedef curlioerr (_curl_ioctl_callback1)(CURL *, int, void*);
+typedef curlioerr (_curl_ioctl_callback2)(CURL *, int, const void*);
+typedef curlioerr (_curl_ioctl_callback3)(CURL *, curliocmd, void*);
+typedef curlioerr (_curl_ioctl_callback4)(CURL *, curliocmd, const void*);
+
+/* evaluates to true if expr is of type curl_sockopt_callback or "similar" */
+#define _curl_is_sockopt_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_sockopt_callback) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback1) || \
+ _curl_callback_compatible((expr), _curl_sockopt_callback2))
+typedef int (_curl_sockopt_callback1)(void *, curl_socket_t, curlsocktype);
+typedef int (_curl_sockopt_callback2)(const void *, curl_socket_t,
+ curlsocktype);
+
+/* evaluates to true if expr is of type curl_opensocket_callback or
+ "similar" */
+#define _curl_is_opensocket_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_opensocket_callback) ||\
+ _curl_callback_compatible((expr), _curl_opensocket_callback1) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback2) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback3) || \
+ _curl_callback_compatible((expr), _curl_opensocket_callback4))
+typedef curl_socket_t (_curl_opensocket_callback1)
+ (void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback2)
+ (void *, curlsocktype, const struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback3)
+ (const void *, curlsocktype, struct curl_sockaddr *);
+typedef curl_socket_t (_curl_opensocket_callback4)
+ (const void *, curlsocktype, const struct curl_sockaddr *);
+
+/* evaluates to true if expr is of type curl_progress_callback or "similar" */
+#define _curl_is_progress_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_progress_callback) || \
+ _curl_callback_compatible((expr), _curl_progress_callback1) || \
+ _curl_callback_compatible((expr), _curl_progress_callback2))
+typedef int (_curl_progress_callback1)(void *,
+ double, double, double, double);
+typedef int (_curl_progress_callback2)(const void *,
+ double, double, double, double);
+
+/* evaluates to true if expr is of type curl_debug_callback or "similar" */
+#define _curl_is_debug_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_debug_callback) || \
+ _curl_callback_compatible((expr), _curl_debug_callback1) || \
+ _curl_callback_compatible((expr), _curl_debug_callback2) || \
+ _curl_callback_compatible((expr), _curl_debug_callback3) || \
+ _curl_callback_compatible((expr), _curl_debug_callback4) || \
+ _curl_callback_compatible((expr), _curl_debug_callback5) || \
+ _curl_callback_compatible((expr), _curl_debug_callback6) || \
+ _curl_callback_compatible((expr), _curl_debug_callback7) || \
+ _curl_callback_compatible((expr), _curl_debug_callback8))
+typedef int (_curl_debug_callback1) (CURL *,
+ curl_infotype, char *, size_t, void *);
+typedef int (_curl_debug_callback2) (CURL *,
+ curl_infotype, char *, size_t, const void *);
+typedef int (_curl_debug_callback3) (CURL *,
+ curl_infotype, const char *, size_t, void *);
+typedef int (_curl_debug_callback4) (CURL *,
+ curl_infotype, const char *, size_t, const void *);
+typedef int (_curl_debug_callback5) (CURL *,
+ curl_infotype, unsigned char *, size_t, void *);
+typedef int (_curl_debug_callback6) (CURL *,
+ curl_infotype, unsigned char *, size_t, const void *);
+typedef int (_curl_debug_callback7) (CURL *,
+ curl_infotype, const unsigned char *, size_t, void *);
+typedef int (_curl_debug_callback8) (CURL *,
+ curl_infotype, const unsigned char *, size_t, const void *);
+
+/* evaluates to true if expr is of type curl_ssl_ctx_callback or "similar" */
+/* this is getting even messier... */
+#define _curl_is_ssl_ctx_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_ssl_ctx_callback) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback1) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback2) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback3) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback4) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback5) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback6) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback7) || \
+ _curl_callback_compatible((expr), _curl_ssl_ctx_callback8))
+typedef CURLcode (_curl_ssl_ctx_callback1)(CURL *, void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback2)(CURL *, void *, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback3)(CURL *, const void *, void *);
+typedef CURLcode (_curl_ssl_ctx_callback4)(CURL *, const void *, const void *);
+#ifdef HEADER_SSL_H
+/* hack: if we included OpenSSL's ssl.h, we know about SSL_CTX
+ * this will of course break if we're included before OpenSSL headers...
+ */
+typedef CURLcode (_curl_ssl_ctx_callback5)(CURL *, SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback6)(CURL *, SSL_CTX, const void *);
+typedef CURLcode (_curl_ssl_ctx_callback7)(CURL *, const SSL_CTX, void *);
+typedef CURLcode (_curl_ssl_ctx_callback8)(CURL *, const SSL_CTX,
+ const void *);
+#else
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback5;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback6;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback7;
+typedef _curl_ssl_ctx_callback1 _curl_ssl_ctx_callback8;
+#endif
+
+/* evaluates to true if expr is of type curl_conv_callback or "similar" */
+#define _curl_is_conv_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_conv_callback) || \
+ _curl_callback_compatible((expr), _curl_conv_callback1) || \
+ _curl_callback_compatible((expr), _curl_conv_callback2) || \
+ _curl_callback_compatible((expr), _curl_conv_callback3) || \
+ _curl_callback_compatible((expr), _curl_conv_callback4))
+typedef CURLcode (*_curl_conv_callback1)(char *, size_t length);
+typedef CURLcode (*_curl_conv_callback2)(const char *, size_t length);
+typedef CURLcode (*_curl_conv_callback3)(void *, size_t length);
+typedef CURLcode (*_curl_conv_callback4)(const void *, size_t length);
+
+/* evaluates to true if expr is of type curl_seek_callback or "similar" */
+#define _curl_is_seek_cb(expr) \
+ (_curl_is_NULL(expr) || \
+ __builtin_types_compatible_p(__typeof__(expr), curl_seek_callback) || \
+ _curl_callback_compatible((expr), _curl_seek_callback1) || \
+ _curl_callback_compatible((expr), _curl_seek_callback2))
+typedef CURLcode (*_curl_seek_callback1)(void *, curl_off_t, int);
+typedef CURLcode (*_curl_seek_callback2)(const void *, curl_off_t, int);
+
+
+#endif /* __CURL_TYPECHECK_GCC_H */
diff --git a/libs/libcurl/libcurl.vcxproj b/libs/libcurl/libcurl.vcxproj
new file mode 100644
index 0000000000..e6214b489a
--- /dev/null
+++ b/libs/libcurl/libcurl.vcxproj
@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectName>libcurl</ProjectName>
+ <ProjectGuid>{01F9E227-06F5-4BED-907F-402CA7DFAFE6}</ProjectGuid>
+ </PropertyGroup>
+ <ImportGroup Label="PropertySheets">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\lib.props" />
+ </ImportGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <PreprocessorDefinitions>BUILDING_LIBCURL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>.\include\;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <AdditionalDependencies>wldap32.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ </ItemDefinitionGroup>
+</Project>
diff --git a/libs/libcurl/libcurl.vcxproj.filters b/libs/libcurl/libcurl.vcxproj.filters
new file mode 100644
index 0000000000..de5ad9f66c
--- /dev/null
+++ b/libs/libcurl/libcurl.vcxproj.filters
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
+</Project> \ No newline at end of file
diff --git a/libs/libcurl/src/README.ares b/libs/libcurl/src/README.ares
new file mode 100644
index 0000000000..8c77937ebd
--- /dev/null
+++ b/libs/libcurl/src/README.ares
@@ -0,0 +1,69 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ How To Build libcurl to Use c-ares For Asynch Name Resolves
+ ===========================================================
+
+c-ares:
+ http://c-ares.haxx.se/
+
+NOTE
+ The latest libcurl version requires c-ares 1.6.0 or later.
+
+ Once upon the time libcurl built fine with the "original" ares. That is no
+ longer true. You need to use c-ares.
+
+Build c-ares
+============
+
+1. unpack the c-ares archive
+2. cd c-ares-dir
+3. ./configure
+4. make
+5. make install
+
+Build libcurl to use c-ares in the curl source tree
+===================================================
+
+1. name or symlink the c-ares source directory 'ares' in the curl source
+ directory
+2. ./configure --enable-ares
+
+ Optionally, you can point out the c-ares install tree root with the the
+ --enable-ares option.
+
+3. make
+
+Build libcurl to use an installed c-ares
+========================================
+
+1. ./configure --enable-ares=/path/to/ares/install
+2. make
+
+c-ares on win32
+===============
+(description brought by Dominick Meglio)
+
+First I compiled c-ares. I changed the default C runtime library to be the
+single-threaded rather than the multi-threaded (this seems to be required to
+prevent linking errors later on). Then I simply build the areslib project (the
+other projects adig/ahost seem to fail under MSVC).
+
+Next was libcurl. I opened lib/config-win32.h and I added a:
+ #define USE_ARES 1
+
+Next thing I did was I added the path for the ares includes to the include
+path, and the libares.lib to the libraries.
+
+Lastly, I also changed libcurl to be single-threaded rather than
+multi-threaded, again this was to prevent some duplicate symbol errors. I'm
+not sure why I needed to change everything to single-threaded, but when I
+didn't I got redefinition errors for several CRT functions (malloc, stricmp,
+etc.)
+
+I would have modified the MSVC++ project files, but I only have VC.NET and it
+uses a different format than VC6.0 so I didn't want to go and change
+everything and remove VC6.0 support from libcurl.
diff --git a/libs/libcurl/src/README.curl_off_t b/libs/libcurl/src/README.curl_off_t
new file mode 100644
index 0000000000..923b2774cd
--- /dev/null
+++ b/libs/libcurl/src/README.curl_off_t
@@ -0,0 +1,68 @@
+
+ curl_off_t explained
+ ====================
+
+curl_off_t is a data type provided by the external libcurl include headers. It
+is the type meant to be used for the curl_easy_setopt() options that end with
+LARGE. The type is 64bit large on most modern platforms.
+
+Transition from < 7.19.0 to >= 7.19.0
+-------------------------------------
+
+Applications that used libcurl before 7.19.0 that are rebuilt with a libcurl
+that is 7.19.0 or later may or may not have to worry about anything of
+this. We have made a significant effort to make the transition really seamless
+and transparent.
+
+You have have to take notice if you are in one of the following situations:
+
+o Your app is using or will after the transition use a libcurl that is built
+ with LFS (large file support) disabled even though your system otherwise
+ supports it.
+
+o Your app is using or will after the transition use a libcurl that doesn't
+ support LFS at all, but your system and compiler support 64bit data types.
+
+In both these cases, the curl_off_t type will now (after the transition) be
+64bit where it previously was 32bit. This will cause a binary incompatibility
+that you MAY need to deal with.
+
+Benefits
+--------
+
+This new way has several benefits:
+
+o Platforms without LFS support can still use libcurl to do >32 bit file
+ transfers and range operations etc as long as they have >32 bit data-types
+ supported.
+
+o Applications will no longer easily build with the curl_off_t size
+ mismatched, which has been a very frequent (and annoying) problem with
+ libcurl <= 7.18.2
+
+Historically
+------------
+
+Previously, before 7.19.0, the curl_off_t type would be rather strongly
+connected to the size of the system off_t type, where currently curl_off_t is
+independent of that.
+
+The strong connection to off_t made it troublesome for application authors
+since when they did mistakes, they could get curl_off_t type of different
+sizes in the app vs libcurl, and that caused strange effects that were hard to
+track and detect by users of libcurl.
+
+SONAME
+------
+
+We opted to not bump the soname for the library unconditionally, simply
+because soname bumping is causing a lot of grief and moaning all over the
+community so we try to keep that at minimum. Also, our selected design path
+should be 100% backwards compatible for the vast majority of all libcurl
+users.
+
+Enforce SONAME bump
+-------------------
+
+If configure doesn't detect your case where a bump is necessary, re-run it
+with the --enable-soname-bump command line option!
diff --git a/libs/libcurl/src/README.curlx b/libs/libcurl/src/README.curlx
new file mode 100644
index 0000000000..5375b0d1d3
--- /dev/null
+++ b/libs/libcurl/src/README.curlx
@@ -0,0 +1,61 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ Source Code Functions Apps Might Use
+ ====================================
+
+The libcurl source code offers a few functions by source only. They are not
+part of the official libcurl API, but the source files might be useful for
+others so apps can optionally compile/build with these sources to gain
+additional functions.
+
+We provide them through a single header file for easy access for apps:
+"curlx.h"
+
+ curlx_strtoofft()
+
+ A macro that converts a string containing a number to a curl_off_t number.
+ This might use the curlx_strtoll() function which is provided as source
+ code in strtoofft.c. Note that the function is only provided if no
+ strtoll() (or equivalent) function exist on your platform. If curl_off_t
+ is only a 32 bit number on your platform, this macro uses strtol().
+
+ curlx_tvnow()
+
+ returns a struct timeval for the current time.
+
+ curlx_tvdiff()
+
+ returns the difference between two timeval structs, in number of
+ milliseconds.
+
+ curlx_tvdiff_secs()
+
+ returns the same as curlx_tvdiff but with full usec resolution (as a
+ double)
+
+FUTURE
+======
+
+ Several functions will be removed from the public curl_ name space in a
+ future libcurl release. They will then only become available as curlx_
+ functions instead. To make the transition easier, we already today provide
+ these functions with the curlx_ prefix to allow sources to get built properly
+ with the new function names. The functions this concerns are:
+
+ curlx_getenv
+ curlx_strequal
+ curlx_strnequal
+ curlx_mvsnprintf
+ curlx_msnprintf
+ curlx_maprintf
+ curlx_mvaprintf
+ curlx_msprintf
+ curlx_mprintf
+ curlx_mfprintf
+ curlx_mvsprintf
+ curlx_mvprintf
+ curlx_mvfprintf
diff --git a/libs/libcurl/src/README.encoding b/libs/libcurl/src/README.encoding
new file mode 100644
index 0000000000..1012bb9eca
--- /dev/null
+++ b/libs/libcurl/src/README.encoding
@@ -0,0 +1,60 @@
+
+ Content Encoding Support for libcurl
+
+* About content encodings:
+
+HTTP/1.1 [RFC 2616] specifies that a client may request that a server encode
+its response. This is usually used to compress a response using one of a set
+of commonly available compression techniques. These schemes are `deflate' (the
+zlib algorithm), `gzip' and `compress' [sec 3.5, RFC 2616]. A client requests
+that the sever perform an encoding by including an Accept-Encoding header in
+the request document. The value of the header should be one of the recognized
+tokens `deflate', ... (there's a way to register new schemes/tokens, see sec
+3.5 of the spec). A server MAY honor the client's encoding request. When a
+response is encoded, the server includes a Content-Encoding header in the
+response. The value of the Content-Encoding header indicates which scheme was
+used to encode the data.
+
+A client may tell a server that it can understand several different encoding
+schemes. In this case the server may choose any one of those and use it to
+encode the response (indicating which one using the Content-Encoding header).
+It's also possible for a client to attach priorities to different schemes so
+that the server knows which it prefers. See sec 14.3 of RFC 2616 for more
+information on the Accept-Encoding header.
+
+* Current support for content encoding:
+
+Support for the 'deflate' and 'gzip' content encoding are supported by
+libcurl. Both regular and chunked transfers should work fine. The library
+zlib is required for this feature. 'deflate' support was added by James
+Gallagher, and support for the 'gzip' encoding was added by Dan Fandrich.
+
+* The libcurl interface:
+
+To cause libcurl to request a content encoding use:
+
+ curl_easy_setopt(curl, CURLOPT_ACCEPT_ENCODING, <string>)
+
+where <string> is the intended value of the Accept-Encoding header.
+
+Currently, libcurl only understands how to process responses that use the
+"deflate" or "gzip" Content-Encoding, so the only values for
+CURLOPT_ACCEPT_ENCODING that will work (besides "identity," which does
+nothing) are "deflate" and "gzip" If a response is encoded using the
+"compress" or methods, libcurl will return an error indicating that the
+response could not be decoded. If <string> is NULL no Accept-Encoding header
+is generated. If <string> is a zero-length string, then an Accept-Encoding
+header containing all supported encodings will be generated.
+
+The CURLOPT_ACCEPT_ENCODING must be set to any non-NULL value for content to
+be automatically decoded. If it is not set and the server still sends encoded
+content (despite not having been asked), the data is returned in its raw form
+and the Content-Encoding type is not checked.
+
+* The curl interface:
+
+Use the --compressed option with curl to cause it to ask servers to compress
+responses using any format supported by curl.
+
+James Gallagher <jgallagher@gso.uri.edu>
+Dan Fandrich <dan@coneharvesters.com>
diff --git a/libs/libcurl/src/README.hostip b/libs/libcurl/src/README.hostip
new file mode 100644
index 0000000000..2e30bc792d
--- /dev/null
+++ b/libs/libcurl/src/README.hostip
@@ -0,0 +1,35 @@
+ hostip.c explained
+ ==================
+
+ The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ source file are these:
+
+ CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ that. The host may not be able to resolve IPv6, but we don't really have to
+ take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ defined.
+
+ CURLRES_ARES - is defined if libcurl is built to use c-ares for asynchronous
+ name resolves. It cannot have ENABLE_IPV6 defined at the same time, as c-ares
+ has no ipv6 support. This can be Windows or *nix.
+
+ CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ Windows, and then the name resolve will be done in a new thread, and the
+ supported asynch API will be the same as for ares-builds.
+
+ If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ defined.
+
+ The host*.c sources files are split up like this:
+
+ hostip.c - method-independent resolver functions and utility functions
+ hostasyn.c - functions for asynchronous name resolves
+ hostsyn.c - functions for synchronous name resolves
+ hostares.c - functions for ares-using name resolves
+ hostthre.c - functions for threaded name resolves
+ hostip4.c - ipv4-specific functions
+ hostip6.c - ipv6-specific functions
+
+ The hostip.h is the single united header file for all this. It defines the
+ CURLRES_* defines based on the config*.h and curl_setup.h defines.
diff --git a/libs/libcurl/src/README.httpauth b/libs/libcurl/src/README.httpauth
new file mode 100644
index 0000000000..9605045107
--- /dev/null
+++ b/libs/libcurl/src/README.httpauth
@@ -0,0 +1,74 @@
+
+1. PUT/POST without a known auth to use (possibly no auth required):
+
+ (When explicitly set to use a multi-pass auth when doing a POST/PUT,
+ libcurl should immediately go the Content-Length: 0 bytes route to avoid
+ the first send all data phase, step 2. If told to use a single-pass auth,
+ goto step 3.)
+
+ Issue the proper PUT/POST request immediately, with the correct
+ Content-Length and Expect: headers.
+
+ If a 100 response is received or the wait for one times out, start sending
+ the request-body.
+
+ If a 401 (or 407 when talking through a proxy) is received, then:
+
+ If we have "more than just a little" data left to send, close the
+ connection. Exactly what "more than just a little" means will have to be
+ determined. Possibly the current transfer speed should be taken into
+ account as well.
+
+ NOTE: if the size of the POST data is less than MAX_INITIAL_POST_SIZE (when
+ CURLOPT_POSTFIELDS is used), libcurl will send everything in one single
+ write() (all request-headers and request-body) and thus it will
+ unconditionally send the full post data here.
+
+2. PUT/POST with multi-pass auth but not yet completely negotiated:
+
+ Send a PUT/POST request, we know that it will be rejected and thus we claim
+ Content-Length zero to avoid having to send the request-body. (This seems
+ to be what IE does.)
+
+3. PUT/POST as the last step in the auth negotiation, that is when we have
+ what we believe is a completed negotiation:
+
+ Send a full and proper PUT/POST request (again) with the proper
+ Content-Length and a following request-body.
+
+ NOTE: this may very well be the second (or even third) time the whole or at
+ least parts of the request body is sent to the server. Since the data may
+ be provided to libcurl with a callback, we need a way to tell the app that
+ the upload is to be restarted so that the callback will provide data from
+ the start again. This requires an API method/mechanism that libcurl
+ doesn't have today. See below.
+
+Data Rewind
+
+ It will be troublesome for some apps to deal with a rewind like this in all
+ circumstances. I'm thinking for example when using 'curl' to upload data
+ from stdin. If libcurl ends up having to rewind the reading for a request
+ to succeed, of course a lack of this callback or if it returns failure, will
+ cause the request to fail completely.
+
+ The new callback is set with CURLOPT_IOCTLFUNCTION (in an attempt to add a
+ more generic function that might be used for other IO-related controls in
+ the future):
+
+ curlioerr curl_ioctl(CURL *handle, curliocmd cmd, void *clientp);
+
+ And in the case where the read is to be rewinded, it would be called with a
+ cmd named CURLIOCMD_RESTARTREAD. The callback would then return CURLIOE_OK,
+ if things are fine, or CURLIOE_FAILRESTART if not.
+
+Backwards Compatibility
+
+ The approach used until now, that issues a HEAD on the given URL to trigger
+ the auth negotiation could still be supported and encouraged, but it would
+ be up to the app to first fetch a URL with GET/HEAD to negotiate on, since
+ then a following PUT/POST wouldn't need to negotiate authentication and
+ thus avoid double-sending data.
+
+ Optionally, we keep the current approach if some option is set
+ (CURLOPT_HEADBEFOREAUTH or similar), since it seems to work fairly well for
+ POST on most servers.
diff --git a/libs/libcurl/src/README.memoryleak b/libs/libcurl/src/README.memoryleak
new file mode 100644
index 0000000000..166177794f
--- /dev/null
+++ b/libs/libcurl/src/README.memoryleak
@@ -0,0 +1,55 @@
+ _ _ ____ _
+ ___| | | | _ \| |
+ / __| | | | |_) | |
+ | (__| |_| | _ <| |___
+ \___|\___/|_| \_\_____|
+
+ How To Track Down Suspected Memory Leaks in libcurl
+ ===================================================
+
+Single-threaded
+
+ Please note that this memory leak system is not adjusted to work in more
+ than one thread. If you want/need to use it in a multi-threaded app. Please
+ adjust accordingly.
+
+
+Build
+
+ Rebuild libcurl with -DCURLDEBUG (usually, rerunning configure with
+ --enable-debug fixes this). 'make clean' first, then 'make' so that all
+ files actually are rebuilt properly. It will also make sense to build
+ libcurl with the debug option (usually -g to the compiler) so that debugging
+ it will be easier if you actually do find a leak in the library.
+
+ This will create a library that has memory debugging enabled.
+
+Modify Your Application
+
+ Add a line in your application code:
+
+ curl_memdebug("dump");
+
+ This will make the malloc debug system output a full trace of all resource
+ using functions to the given file name. Make sure you rebuild your program
+ and that you link with the same libcurl you built for this purpose as
+ described above.
+
+Run Your Application
+
+ Run your program as usual. Watch the specified memory trace file grow.
+
+ Make your program exit and use the proper libcurl cleanup functions etc. So
+ that all non-leaks are returned/freed properly.
+
+Analyze the Flow
+
+ Use the tests/memanalyze.pl perl script to analyze the dump file:
+
+ tests/memanalyze.pl dump
+
+ This now outputs a report on what resources that were allocated but never
+ freed etc. This report is very fine for posting to the list!
+
+ If this doesn't produce any output, no leak was detected in libcurl. Then
+ the leak is mostly likely to be in your code.
diff --git a/libs/libcurl/src/README.multi_socket b/libs/libcurl/src/README.multi_socket
new file mode 100644
index 0000000000..d91e1d9f27
--- /dev/null
+++ b/libs/libcurl/src/README.multi_socket
@@ -0,0 +1,53 @@
+Implementation of the curl_multi_socket API
+
+ The main ideas of the new API are simply:
+
+ 1 - The application can use whatever event system it likes as it gets info
+ from libcurl about what file descriptors libcurl waits for what action
+ on. (The previous API returns fd_sets which is very select()-centric).
+
+ 2 - When the application discovers action on a single socket, it calls
+ libcurl and informs that there was action on this particular socket and
+ libcurl can then act on that socket/transfer only and not care about
+ any other transfers. (The previous API always had to scan through all
+ the existing transfers.)
+
+ The idea is that curl_multi_socket_action() calls a given callback with
+ information about what socket to wait for what action on, and the callback
+ only gets called if the status of that socket has changed.
+
+ We also added a timer callback that makes libcurl call the application when
+ the timeout value changes, and you set that with curl_multi_setopt() and the
+ CURLMOPT_TIMERFUNCTION option. To get this to work, Internally, there's an
+ added a struct to each easy handle in which we store an "expire time" (if
+ any). The structs are then "splay sorted" so that we can add and remove
+ times from the linked list and yet somewhat swiftly figure out both how long
+ time there is until the next nearest timer expires and which timer (handle)
+ we should take care of now. Of course, the upside of all this is that we get
+ a curl_multi_timeout() that should also work with old-style applications
+ that use curl_multi_perform().
+
+ We created an internal "socket to easy handles" hash table that given
+ a socket (file descriptor) return the easy handle that waits for action on
+ that socket. This hash is made using the already existing hash code
+ (previously only used for the DNS cache).
+
+ To make libcurl able to report plain sockets in the socket callback, we had
+ to re-organize the internals of the curl_multi_fdset() etc so that the
+ conversion from sockets to fd_sets for that function is only done in the
+ last step before the data is returned. I also had to extend c-ares to get a
+ function that can return plain sockets, as that library too returned only
+ fd_sets and that is no longer good enough. The changes done to c-ares are
+ available in c-ares 1.3.1 and later.
+
+ We have done a test runs with up to 9000 connections (with a single active
+ one). The curl_multi_socket_action() invoke then takes less than 10
+ microseconds in average (using the read-only-1-byte-at-a-time hack). We are
+ now below the 60 microseconds "per socket action" goal (the extra 50 is the
+ time libevent needs).
+
+Documentation
+
+ http://curl.haxx.se/libcurl/c/curl_multi_socket_action.html
+ http://curl.haxx.se/libcurl/c/curl_multi_timeout.html
+ http://curl.haxx.se/libcurl/c/curl_multi_setopt.html
diff --git a/libs/libcurl/src/README.pingpong b/libs/libcurl/src/README.pingpong
new file mode 100644
index 0000000000..69ba9aadbf
--- /dev/null
+++ b/libs/libcurl/src/README.pingpong
@@ -0,0 +1,30 @@
+Date: December 5, 2009
+
+Pingpong
+========
+
+ Pingpong is just my (Daniel's) jestful collective name on the protocols that
+ share a very similar kind of back-and-forth procedure with command and
+ responses to and from the server. FTP was previously the only protocol in
+ that family that libcurl supported, but when POP3, IMAP and SMTP joined the
+ team I moved some of the internals into a separate pingpong module to be
+ easier to get used by all these protocols to reduce code duplication and ease
+ code re-use between these protocols.
+
+FTP
+
+ In 7.20.0 we converted code to use the new pingpong code from previously
+ having been all "native" FTP code.
+
+POP3
+
+ There's no support in the documented URL format to specify the exact mail to
+ get, but we support that as the path specified in the URL.
+
+IMAP
+
+SMTP
+
+ There's no official URL syntax defined for SMTP, but we use only the generic
+ one and we provide two additional libcurl options to specify receivers and
+ sender of the actual mail.
diff --git a/libs/libcurl/src/README.pipelining b/libs/libcurl/src/README.pipelining
new file mode 100644
index 0000000000..c7b462248a
--- /dev/null
+++ b/libs/libcurl/src/README.pipelining
@@ -0,0 +1,51 @@
+HTTP Pipelining with libcurl
+============================
+
+Background
+
+Since pipelining implies that one or more requests are sent to a server before
+the previous response(s) have been received, we only support it for multi
+interface use.
+
+Considerations
+
+When using the multi interface, you create one easy handle for each transfer.
+Bascially any number of handles can be created, added and used with the multi
+interface - simultaneously. It is an interface designed to allow many
+simultaneous transfers while still using a single thread. Pipelining does not
+change any of these details.
+
+API
+
+We've added a new option to curl_multi_setopt() called CURLMOPT_PIPELINING
+that enables "attempted pipelining" and then all easy handles used on that
+handle will attempt to use an existing pipeline.
+
+Details
+
+- A pipeline is only created if a previous connection exists to the same IP
+ address that the new request is being made to use.
+
+- Pipelines are only supported for HTTP(S) as no other currently supported
+ protocol has features resemembling this, but we still name this feature
+ plain 'pipelining' to possibly one day support it for other protocols as
+ well.
+
+- HTTP Pipelining is for GET and HEAD requests only.
+
+- When a pipeline is in use, we must take precautions so that when used easy
+ handles (i.e those who still wait for a response) are removed from the multi
+ handle, we must deal with the outstanding response nicely.
+
+- Explicitly asking for pipelining handle X and handle Y won't be supported.
+ It isn't easy for an app to do this association. The lib should probably
+ still resolve the second one properly to make sure that they actually _can_
+ be considered for pipelining. Also, asking for explicit pipelining on handle
+ X may be tricky when handle X get a closed connection.
+
+- We need options to control max pipeline length, and probably how to behave
+ if we reach that limit. As was discussed on the list, it can probably be
+ made very complicated, so perhaps we can think of a way to pass all
+ variables involved to a callback and let the application decide how to act
+ in specific situations. Either way, these fancy options are only interesting
+ to work on when everything is working and we have working apps to test with.
diff --git a/libs/libcurl/src/amigaos.c b/libs/libcurl/src/amigaos.c
new file mode 100644
index 0000000000..34f95e9b5c
--- /dev/null
+++ b/libs/libcurl/src/amigaos.c
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(__AMIGA__) && !defined(__ixemul__)
+
+#include <amitcp/socketbasetags.h>
+
+#include "amigaos.h"
+
+struct Library *SocketBase = NULL;
+extern int errno, h_errno;
+
+#ifdef __libnix__
+#include <stabs.h>
+void __request(const char *msg);
+#else
+# define __request( msg ) Printf( msg "\n\a")
+#endif
+
+void Curl_amiga_cleanup()
+{
+ if(SocketBase) {
+ CloseLibrary(SocketBase);
+ SocketBase = NULL;
+ }
+}
+
+bool Curl_amiga_init()
+{
+ if(!SocketBase)
+ SocketBase = OpenLibrary("bsdsocket.library", 4);
+
+ if(!SocketBase) {
+ __request("No TCP/IP Stack running!");
+ return FALSE;
+ }
+
+ if(SocketBaseTags(SBTM_SETVAL(SBTC_ERRNOPTR(sizeof(errno))), (ULONG) &errno,
+ SBTM_SETVAL(SBTC_LOGTAGPTR), (ULONG) "cURL",
+ TAG_DONE)) {
+ __request("SocketBaseTags ERROR");
+ return FALSE;
+ }
+
+#ifndef __libnix__
+ atexit(Curl_amiga_cleanup);
+#endif
+
+ return TRUE;
+}
+
+#ifdef __libnix__
+ADD2EXIT(Curl_amiga_cleanup,-50);
+#endif
+
+#endif /* __AMIGA__ && ! __ixemul__ */
diff --git a/libs/libcurl/src/amigaos.h b/libs/libcurl/src/amigaos.h
new file mode 100644
index 0000000000..76578be868
--- /dev/null
+++ b/libs/libcurl/src/amigaos.h
@@ -0,0 +1,39 @@
+#ifndef HEADER_CURL_AMIGAOS_H
+#define HEADER_CURL_AMIGAOS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(__AMIGA__) && !defined(__ixemul__)
+
+bool Curl_amiga_init();
+void Curl_amiga_cleanup();
+
+#else
+
+#define Curl_amiga_init() 1
+#define Curl_amiga_cleanup() Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_AMIGAOS_H */
+
diff --git a/libs/libcurl/src/arpa_telnet.h b/libs/libcurl/src/arpa_telnet.h
new file mode 100644
index 0000000000..098d9a92f7
--- /dev/null
+++ b/libs/libcurl/src/arpa_telnet.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_ARPA_TELNET_H
+#define HEADER_CURL_ARPA_TELNET_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+/*
+ * Telnet option defines. Add more here if in need.
+ */
+#define CURL_TELOPT_BINARY 0 /* binary 8bit data */
+#define CURL_TELOPT_ECHO 1 /* just echo! */
+#define CURL_TELOPT_SGA 3 /* Suppress Go Ahead */
+#define CURL_TELOPT_EXOPL 255 /* EXtended OPtions List */
+#define CURL_TELOPT_TTYPE 24 /* Terminal TYPE */
+#define CURL_TELOPT_NAWS 31 /* Negotiate About Window Size */
+#define CURL_TELOPT_XDISPLOC 35 /* X DISPlay LOCation */
+
+#define CURL_TELOPT_NEW_ENVIRON 39 /* NEW ENVIRONment variables */
+#define CURL_NEW_ENV_VAR 0
+#define CURL_NEW_ENV_VALUE 1
+
+/*
+ * The telnet options represented as strings
+ */
+static const char * const telnetoptions[]=
+{
+ "BINARY", "ECHO", "RCP", "SUPPRESS GO AHEAD",
+ "NAME", "STATUS", "TIMING MARK", "RCTE",
+ "NAOL", "NAOP", "NAOCRD", "NAOHTS",
+ "NAOHTD", "NAOFFD", "NAOVTS", "NAOVTD",
+ "NAOLFD", "EXTEND ASCII", "LOGOUT", "BYTE MACRO",
+ "DE TERMINAL", "SUPDUP", "SUPDUP OUTPUT", "SEND LOCATION",
+ "TERM TYPE", "END OF RECORD", "TACACS UID", "OUTPUT MARKING",
+ "TTYLOC", "3270 REGIME", "X3 PAD", "NAWS",
+ "TERM SPEED", "LFLOW", "LINEMODE", "XDISPLOC",
+ "OLD-ENVIRON", "AUTHENTICATION", "ENCRYPT", "NEW-ENVIRON"
+};
+
+#define CURL_TELOPT_MAXIMUM CURL_TELOPT_NEW_ENVIRON
+
+#define CURL_TELOPT_OK(x) ((x) <= CURL_TELOPT_MAXIMUM)
+#define CURL_TELOPT(x) telnetoptions[x]
+
+#define CURL_NTELOPTS 40
+
+/*
+ * First some defines
+ */
+#define CURL_xEOF 236 /* End Of File */
+#define CURL_SE 240 /* Sub negotiation End */
+#define CURL_NOP 241 /* No OPeration */
+#define CURL_DM 242 /* Data Mark */
+#define CURL_GA 249 /* Go Ahead, reverse the line */
+#define CURL_SB 250 /* SuBnegotiation */
+#define CURL_WILL 251 /* Our side WILL use this option */
+#define CURL_WONT 252 /* Our side WON'T use this option */
+#define CURL_DO 253 /* DO use this option! */
+#define CURL_DONT 254 /* DON'T use this option! */
+#define CURL_IAC 255 /* Interpret As Command */
+
+/*
+ * Then those numbers represented as strings:
+ */
+static const char * const telnetcmds[]=
+{
+ "EOF", "SUSP", "ABORT", "EOR", "SE",
+ "NOP", "DMARK", "BRK", "IP", "AO",
+ "AYT", "EC", "EL", "GA", "SB",
+ "WILL", "WONT", "DO", "DONT", "IAC"
+};
+
+#define CURL_TELCMD_MINIMUM CURL_xEOF /* the first one */
+#define CURL_TELCMD_MAXIMUM CURL_IAC /* surprise, 255 is the last one! ;-) */
+
+#define CURL_TELQUAL_IS 0
+#define CURL_TELQUAL_SEND 1
+#define CURL_TELQUAL_INFO 2
+#define CURL_TELQUAL_NAME 3
+
+#define CURL_TELCMD_OK(x) ( ((unsigned int)(x) >= CURL_TELCMD_MINIMUM) && \
+ ((unsigned int)(x) <= CURL_TELCMD_MAXIMUM) )
+#define CURL_TELCMD(x) telnetcmds[(x)-CURL_TELCMD_MINIMUM]
+
+#endif /* CURL_DISABLE_TELNET */
+
+#endif /* HEADER_CURL_ARPA_TELNET_H */
diff --git a/libs/libcurl/src/asyn-ares.c b/libs/libcurl/src/asyn-ares.c
new file mode 100644
index 0000000000..0ef36cbbe2
--- /dev/null
+++ b/libs/libcurl/src/asyn-ares.c
@@ -0,0 +1,694 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_LIMITS_H
+#include <limits.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/***********************************************************************
+ * Only for ares-enabled builds
+ * And only for functions that fulfill the asynch resolver backend API
+ * as defined in asyn.h, nothing else belongs in this file!
+ **********************************************************************/
+
+#ifdef CURLRES_ARES
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+# define CARES_STATICLIB
+# endif
+# include <ares.h>
+# include <ares_version.h> /* really old c-ares didn't include this by
+ itself */
+
+#if ARES_VERSION >= 0x010500
+/* c-ares 1.5.0 or later, the callback proto is modified */
+#define HAVE_CARES_CALLBACK_TIMEOUTS 1
+#endif
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct ResolverResults {
+ int num_pending; /* number of ares_gethostbyname() requests */
+ Curl_addrinfo *temp_ai; /* intermediary result while fetching c-ares parts */
+ int last_status;
+};
+
+/*
+ * Curl_resolver_global_init() - the generic low-level asynchronous name
+ * resolve API. Called from curl_global_init() to initialize global resolver
+ * environment. Initializes ares library.
+ */
+int Curl_resolver_global_init(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_INIT
+ if(ares_library_init(ARES_LIB_INIT_ALL)) {
+ return CURLE_FAILED_INIT;
+ }
+#endif
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ *
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Deinitializes ares library.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+#ifdef CARES_HAVE_ARES_LIBRARY_CLEANUP
+ ares_library_cleanup();
+#endif
+}
+
+/*
+ * Curl_resolver_init()
+ *
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Fills the passed pointer by the initialized ares_channel.
+ */
+CURLcode Curl_resolver_init(void **resolver)
+{
+ int status = ares_init((ares_channel*)resolver);
+ if(status != ARES_SUCCESS) {
+ if(status == ARES_ENOMEM)
+ return CURLE_OUT_OF_MEMORY;
+ else
+ return CURLE_FAILED_INIT;
+ }
+ return CURLE_OK;
+ /* make sure that all other returns from this function should destroy the
+ ares channel before returning error! */
+}
+
+/*
+ * Curl_resolver_cleanup()
+ *
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Destroys the ares channel.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+ ares_destroy((ares_channel)resolver);
+}
+
+/*
+ * Curl_resolver_duphandle()
+ *
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure). Duplicates the
+ * 'from' ares channel and passes the resulting channel to the 'to' pointer.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+ /* Clone the ares channel for the new handle */
+ if(ARES_SUCCESS != ares_dup((ares_channel*)to,(ares_channel)from))
+ return CURLE_FAILED_INIT;
+ return CURLE_OK;
+}
+
+static void destroy_async_data (struct Curl_async *async);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+ if(conn && conn->data && conn->data->state.resolver)
+ ares_cancel((ares_channel)conn->data->state.resolver);
+ destroy_async_data(&conn->async);
+}
+
+/*
+ * destroy_async_data() cleans up async resolver data.
+ */
+static void destroy_async_data (struct Curl_async *async)
+{
+ if(async->hostname)
+ free(async->hostname);
+
+ if(async->os_specific) {
+ struct ResolverResults *res = (struct ResolverResults *)async->os_specific;
+ if(res) {
+ if(res->temp_ai) {
+ Curl_freeaddrinfo(res->temp_ai);
+ res->temp_ai = NULL;
+ }
+ free(res);
+ }
+ async->os_specific = NULL;
+ }
+
+ async->hostname = NULL;
+}
+
+/*
+ * Curl_resolver_getsock() is called when someone from the outside world
+ * (using curl_multi_fdset()) wants to get our fd_set setup and we're talking
+ * with ares. The caller must make sure that this function is only called when
+ * we have a working ares channel.
+ *
+ * Returns: sockets-in-use-bitmap
+ */
+
+int Curl_resolver_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+
+{
+ struct timeval maxtime;
+ struct timeval timebuf;
+ struct timeval *timeout;
+ long milli;
+ int max = ares_getsock((ares_channel)conn->data->state.resolver,
+ (ares_socket_t *)socks, numsocks);
+
+ maxtime.tv_sec = CURL_TIMEOUT_RESOLVE;
+ maxtime.tv_usec = 0;
+
+ timeout = ares_timeout((ares_channel)conn->data->state.resolver, &maxtime,
+ &timebuf);
+ milli = (timeout->tv_sec * 1000) + (timeout->tv_usec/1000);
+ if(milli == 0)
+ milli += 10;
+ Curl_expire(conn->data, milli);
+
+ return max;
+}
+
+/*
+ * waitperform()
+ *
+ * 1) Ask ares what sockets it currently plays with, then
+ * 2) wait for the timeout period to check for action on ares' sockets.
+ * 3) tell ares to act on all the sockets marked as "with action"
+ *
+ * return number of sockets it worked on
+ */
+
+static int waitperform(struct connectdata *conn, int timeout_ms)
+{
+ struct SessionHandle *data = conn->data;
+ int nfds;
+ int bitmask;
+ ares_socket_t socks[ARES_GETSOCK_MAXNUM];
+ struct pollfd pfd[ARES_GETSOCK_MAXNUM];
+ int i;
+ int num = 0;
+
+ bitmask = ares_getsock((ares_channel)data->state.resolver, socks,
+ ARES_GETSOCK_MAXNUM);
+
+ for(i=0; i < ARES_GETSOCK_MAXNUM; i++) {
+ pfd[i].events = 0;
+ pfd[i].revents = 0;
+ if(ARES_GETSOCK_READABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLRDNORM|POLLIN;
+ }
+ if(ARES_GETSOCK_WRITABLE(bitmask, i)) {
+ pfd[i].fd = socks[i];
+ pfd[i].events |= POLLWRNORM|POLLOUT;
+ }
+ if(pfd[i].events != 0)
+ num++;
+ else
+ break;
+ }
+
+ if(num)
+ nfds = Curl_poll(pfd, num, timeout_ms);
+ else
+ nfds = 0;
+
+ if(!nfds)
+ /* Call ares_process() unconditonally here, even if we simply timed out
+ above, as otherwise the ares name resolve won't timeout! */
+ ares_process_fd((ares_channel)data->state.resolver, ARES_SOCKET_BAD,
+ ARES_SOCKET_BAD);
+ else {
+ /* move through the descriptors and ask for processing on them */
+ for(i=0; i < num; i++)
+ ares_process_fd((ares_channel)data->state.resolver,
+ pfd[i].revents & (POLLRDNORM|POLLIN)?
+ pfd[i].fd:ARES_SOCKET_BAD,
+ pfd[i].revents & (POLLWRNORM|POLLOUT)?
+ pfd[i].fd:ARES_SOCKET_BAD);
+ }
+ return nfds;
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns)
+{
+ struct SessionHandle *data = conn->data;
+ struct ResolverResults *res = (struct ResolverResults *)
+ conn->async.os_specific;
+ CURLcode rc = CURLE_OK;
+
+ *dns = NULL;
+
+ waitperform(conn, 0);
+
+ if(res && !res->num_pending) {
+ (void)Curl_addrinfo_callback(conn, res->last_status, res->temp_ai);
+ /* temp_ai ownership is moved to the connection, so we need not free-up
+ them */
+ res->temp_ai = NULL;
+ if(!conn->async.dns) {
+ 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 rc;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ CURLcode rc=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ long timeout;
+ struct timeval now = Curl_tvnow();
+ struct Curl_dns_entry *temp_entry;
+
+ timeout = Curl_timeleft(data, &now, TRUE);
+ if(!timeout)
+ timeout = CURL_TIMEOUT_RESOLVE * 1000; /* default name resolve timeout */
+
+ /* Wait for the name resolve query to complete. */
+ for(;;) {
+ struct timeval *tvp, tv, store;
+ long timediff;
+ int itimeout;
+ int timeout_ms;
+
+ itimeout = (timeout > (long)INT_MAX) ? INT_MAX : (int)timeout;
+
+ store.tv_sec = itimeout/1000;
+ store.tv_usec = (itimeout%1000)*1000;
+
+ tvp = ares_timeout((ares_channel)data->state.resolver, &store, &tv);
+
+ /* use the timeout period ares returned to us above if less than one
+ second is left, otherwise just use 1000ms to make sure the progress
+ callback gets called frequent enough */
+ if(!tvp->tv_sec)
+ timeout_ms = (int)(tvp->tv_usec/1000);
+ else
+ timeout_ms = 1000;
+
+ waitperform(conn, timeout_ms);
+ Curl_resolver_is_resolved(conn,&temp_entry);
+
+ if(conn->async.done)
+ break;
+
+ if(Curl_pgrsUpdate(conn)) {
+ rc = CURLE_ABORTED_BY_CALLBACK;
+ timeout = -1; /* trigger the cancel below */
+ }
+ else {
+ struct timeval now2 = Curl_tvnow();
+ timediff = Curl_tvdiff(now2, now); /* spent time */
+ timeout -= timediff?timediff:1; /* always deduct at least 1 */
+ now = now2; /* for next loop */
+ }
+ if(timeout < 0) {
+ /* our timeout, so we cancel the ares operation */
+ ares_cancel((ares_channel)data->state.resolver);
+ break;
+ }
+ }
+
+ /* Operation complete, if the lookup was successful we now have the entry
+ in the cache. */
+
+ if(entry)
+ *entry = conn->async.dns;
+
+ if(rc)
+ /* close the connection, since we can't return failure here without
+ cleaning up this connection properly.
+ TODO: remove this action from here, it is not a name resolver decision.
+ */
+ conn->bits.close = TRUE;
+
+ return rc;
+}
+
+/* Connects results to the list */
+static void compound_results(struct ResolverResults *res,
+ Curl_addrinfo *ai)
+{
+ Curl_addrinfo *ai_tail;
+ if(!ai)
+ return;
+ ai_tail = ai;
+
+ while(ai_tail->ai_next)
+ ai_tail = ai_tail->ai_next;
+
+ /* Add the new results to the list of old results. */
+ ai_tail->ai_next = res->temp_ai;
+ res->temp_ai = ai;
+}
+
+/*
+ * ares_query_completed_cb() is the callback that ares will call when
+ * the host query initiated by ares_gethostbyname() from Curl_getaddrinfo(),
+ * when using ares, is completed either successfully or with failure.
+ */
+static void query_completed_cb(void *arg, /* (struct connectdata *) */
+ int status,
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+ int timeouts,
+#endif
+ struct hostent *hostent)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ struct ResolverResults *res;
+
+#ifdef HAVE_CARES_CALLBACK_TIMEOUTS
+ (void)timeouts; /* ignored */
+#endif
+
+ if(ARES_EDESTRUCTION == status)
+ /* when this ares handle is getting destroyed, the 'arg' pointer may not
+ be valid so only defer it when we know the 'status' says its fine! */
+ return;
+
+ res = (struct ResolverResults *)conn->async.os_specific;
+ res->num_pending--;
+
+ if(CURL_ASYNC_SUCCESS == status) {
+ Curl_addrinfo *ai = Curl_he2ai(hostent, conn->async.port);
+ if(ai) {
+ compound_results(res, ai);
+ }
+ }
+ /* A successful result overwrites any previous error */
+ if(res->last_status != ARES_SUCCESS)
+ res->last_status = status;
+}
+
+/*
+ * Curl_resolver_getaddrinfo() - when using ares
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ char *bufp;
+ struct SessionHandle *data = conn->data;
+ struct in_addr in;
+ int family = PF_INET;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+ *waitp = 0; /* default to synchronous response */
+
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0) {
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+ }
+
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ /* Otherwise, check if this is an IPv6 address string */
+ if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
+ /* This must be an IPv6 address literal. */
+ return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+
+ switch(conn->ip_version) {
+ default:
+#if ARES_VERSION >= 0x010601
+ family = PF_UNSPEC; /* supported by c-ares since 1.6.1, so for older
+ c-ares versions this just falls through and defaults
+ to PF_INET */
+ break;
+#endif
+ case CURL_IPRESOLVE_V4:
+ family = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ family = PF_INET6;
+ break;
+ }
+#endif /* CURLRES_IPV6 */
+
+ bufp = strdup(hostname);
+ if(bufp) {
+ struct ResolverResults *res = NULL;
+ Curl_safefree(conn->async.hostname);
+ conn->async.hostname = bufp;
+ conn->async.port = port;
+ conn->async.done = FALSE; /* not done */
+ conn->async.status = 0; /* clear */
+ conn->async.dns = NULL; /* clear */
+ res = calloc(sizeof(struct ResolverResults),1);
+ if(!res) {
+ Curl_safefree(conn->async.hostname);
+ conn->async.hostname = NULL;
+ return NULL;
+ }
+ conn->async.os_specific = res;
+
+ /* initial status - failed */
+ res->last_status = ARES_ENOTFOUND;
+#ifdef ENABLE_IPV6 /* CURLRES_IPV6 */
+ if(family == PF_UNSPEC) {
+ if(Curl_ipv6works()) {
+ res->num_pending = 2;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET, query_completed_cb, conn);
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET6, query_completed_cb, conn);
+ }
+ else {
+ res->num_pending = 1;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname,
+ PF_INET, query_completed_cb, conn);
+ }
+ }
+ else
+#endif /* CURLRES_IPV6 */
+ {
+ res->num_pending = 1;
+
+ /* areschannel is already setup in the Curl_open() function */
+ ares_gethostbyname((ares_channel)data->state.resolver, hostname, family,
+ query_completed_cb, conn);
+ }
+
+ *waitp = 1; /* expect asynchronous response */
+ }
+ return NULL; /* no struct yet */
+}
+
+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)
+ ares_result = ares_set_servers_csv(data->state.resolver, servers);
+ switch(ares_result) {
+ case ARES_SUCCESS:
+ result = CURLE_OK;
+ break;
+ case ARES_ENOMEM:
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ case ARES_ENOTINITIALIZED:
+ case ARES_ENODATA:
+ case ARES_EBADSTR:
+ default:
+ result = CURLE_BAD_FUNCTION_ARGUMENT;
+ break;
+ }
+#else /* too old c-ares version! */
+ (void)data;
+ (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 */
diff --git a/libs/libcurl/src/asyn-thread.c b/libs/libcurl/src/asyn-thread.c
new file mode 100644
index 0000000000..4882c37203
--- /dev/null
+++ b/libs/libcurl/src/asyn-thread.c
@@ -0,0 +1,662 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#ifdef HAVE_GETADDRINFO
+# define RESOLVER_ENOMEM EAI_MEMORY
+#else
+# define RESOLVER_ENOMEM ENOMEM
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "multiif.h"
+#include "inet_pton.h"
+#include "inet_ntop.h"
+#include "curl_threads.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"
+
+/***********************************************************************
+ * Only for threaded name resolves builds
+ **********************************************************************/
+#ifdef CURLRES_THREADED
+
+/*
+ * Curl_resolver_global_init()
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Does nothing here.
+ */
+int Curl_resolver_global_init(void)
+{
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ * Does nothing here.
+ */
+void Curl_resolver_global_cleanup(void)
+{
+}
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Does nothing here.
+ */
+CURLcode Curl_resolver_init(void **resolver)
+{
+ (void)resolver;
+ return CURLE_OK;
+}
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Does nothing here.
+ */
+void Curl_resolver_cleanup(void *resolver)
+{
+ (void)resolver;
+}
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL state-specific
+ * environment ('resolver' member of the UrlState structure). Does nothing
+ * here.
+ */
+int Curl_resolver_duphandle(void **to, void *from)
+{
+ (void)to;
+ (void)from;
+ return CURLE_OK;
+}
+
+static void destroy_async_data(struct Curl_async *);
+
+/*
+ * Cancel all possibly still on-going resolves for this connection.
+ */
+void Curl_resolver_cancel(struct connectdata *conn)
+{
+ destroy_async_data(&conn->async);
+}
+
+/* This function is used to init a threaded resolve */
+static bool init_resolve_thread(struct connectdata *conn,
+ const char *hostname, int port,
+ const struct addrinfo *hints);
+
+
+/* Data for synchronization between resolver thread and its parent */
+struct thread_sync_data {
+ curl_mutex_t * mtx;
+ int done;
+
+ char * hostname; /* hostname to resolve, Curl_async.hostname
+ duplicate */
+ int port;
+ int sock_error;
+ Curl_addrinfo *res;
+#ifdef HAVE_GETADDRINFO
+ struct addrinfo hints;
+#endif
+};
+
+struct thread_data {
+ curl_thread_t thread_hnd;
+ unsigned int poll_interval;
+ long interval_end;
+ struct thread_sync_data tsd;
+};
+
+static struct thread_sync_data *conn_thread_sync_data(struct connectdata *conn)
+{
+ return &(((struct thread_data *)conn->async.os_specific)->tsd);
+}
+
+#define CONN_THREAD_SYNC_DATA(conn) &(((conn)->async.os_specific)->tsd);
+
+/* Destroy resolver thread synchronization data */
+static
+void destroy_thread_sync_data(struct thread_sync_data * tsd)
+{
+ if(tsd->mtx) {
+ Curl_mutex_destroy(tsd->mtx);
+ free(tsd->mtx);
+ }
+
+ if(tsd->hostname)
+ free(tsd->hostname);
+
+ if(tsd->res)
+ Curl_freeaddrinfo(tsd->res);
+
+ memset(tsd,0,sizeof(*tsd));
+}
+
+/* Initialize resolver thread synchronization data */
+static
+int init_thread_sync_data(struct thread_sync_data * tsd,
+ const char * hostname,
+ int port,
+ const struct addrinfo *hints)
+{
+ memset(tsd, 0, sizeof(*tsd));
+
+ tsd->port = port;
+#ifdef CURLRES_IPV6
+ DEBUGASSERT(hints);
+ tsd->hints = *hints;
+#else
+ (void) hints;
+#endif
+
+ tsd->mtx = malloc(sizeof(curl_mutex_t));
+ if(tsd->mtx == NULL)
+ goto err_exit;
+
+ Curl_mutex_init(tsd->mtx);
+
+ tsd->sock_error = CURL_ASYNC_SUCCESS;
+
+ /* Copying hostname string because original can be destroyed by parent
+ * thread during gethostbyname execution.
+ */
+ tsd->hostname = strdup(hostname);
+ if(!tsd->hostname)
+ goto err_exit;
+
+ return 1;
+
+ err_exit:
+ /* Memory allocation failed */
+ destroy_thread_sync_data(tsd);
+ return 0;
+}
+
+static int getaddrinfo_complete(struct connectdata *conn)
+{
+ struct thread_sync_data *tsd = conn_thread_sync_data(conn);
+ int rc;
+
+ rc = Curl_addrinfo_callback(conn, tsd->sock_error, tsd->res);
+ /* The tsd->res structure has been copied to async.dns and perhaps the DNS
+ cache. Set our copy to NULL so destroy_thread_sync_data doesn't free it.
+ */
+ tsd->res = NULL;
+
+ return rc;
+}
+
+
+#ifdef HAVE_GETADDRINFO
+
+/*
+ * getaddrinfo_thread() resolves a name and then exits.
+ *
+ * For builds without ARES, but with ENABLE_IPV6, create a resolver thread
+ * and wait on it.
+ */
+static unsigned int CURL_STDCALL getaddrinfo_thread (void *arg)
+{
+ struct thread_sync_data *tsd = (struct thread_sync_data*)arg;
+ char service[12];
+ int rc;
+
+ snprintf(service, sizeof(service), "%d", tsd->port);
+
+ rc = Curl_getaddrinfo_ex(tsd->hostname, service, &tsd->hints, &tsd->res);
+
+ if(rc != 0) {
+ tsd->sock_error = SOCKERRNO?SOCKERRNO:rc;
+ if(tsd->sock_error == 0)
+ tsd->sock_error = RESOLVER_ENOMEM;
+ }
+
+ Curl_mutex_acquire(tsd->mtx);
+ tsd->done = 1;
+ Curl_mutex_release(tsd->mtx);
+
+ return 0;
+}
+
+#else /* HAVE_GETADDRINFO */
+
+/*
+ * gethostbyname_thread() resolves a name and then exits.
+ */
+static unsigned int CURL_STDCALL gethostbyname_thread (void *arg)
+{
+ struct thread_sync_data *tsd = (struct thread_sync_data *)arg;
+
+ tsd->res = Curl_ipv4_resolve_r(tsd->hostname, tsd->port);
+
+ if(!tsd->res) {
+ tsd->sock_error = SOCKERRNO;
+ if(tsd->sock_error == 0)
+ tsd->sock_error = RESOLVER_ENOMEM;
+ }
+
+ Curl_mutex_acquire(tsd->mtx);
+ tsd->done = 1;
+ Curl_mutex_release(tsd->mtx);
+
+ return 0;
+}
+
+#endif /* HAVE_GETADDRINFO */
+
+/*
+ * destroy_async_data() cleans up async resolver data and thread handle.
+ */
+static void destroy_async_data (struct Curl_async *async)
+{
+ if(async->hostname)
+ free(async->hostname);
+
+ if(async->os_specific) {
+ struct thread_data *td = (struct thread_data*) async->os_specific;
+
+ if(td->thread_hnd != curl_thread_t_null)
+ Curl_thread_join(&td->thread_hnd);
+
+ destroy_thread_sync_data(&td->tsd);
+
+ free(async->os_specific);
+ }
+ async->hostname = NULL;
+ async->os_specific = NULL;
+}
+
+/*
+ * init_resolve_thread() starts a new thread that performs the actual
+ * resolve. This function returns before the resolve is done.
+ *
+ * Returns FALSE in case of failure, otherwise TRUE.
+ */
+static bool init_resolve_thread (struct connectdata *conn,
+ const char *hostname, int port,
+ const struct addrinfo *hints)
+{
+ struct thread_data *td = calloc(1, sizeof(struct thread_data));
+ int err = RESOLVER_ENOMEM;
+
+ conn->async.os_specific = (void*) td;
+ if(!td)
+ goto err_exit;
+
+ conn->async.port = port;
+ conn->async.done = FALSE;
+ conn->async.status = 0;
+ conn->async.dns = NULL;
+ td->thread_hnd = curl_thread_t_null;
+
+ if(!init_thread_sync_data(&td->tsd, hostname, port, hints))
+ goto err_exit;
+
+ Curl_safefree(conn->async.hostname);
+ conn->async.hostname = strdup(hostname);
+ if(!conn->async.hostname)
+ goto err_exit;
+
+#ifdef HAVE_GETADDRINFO
+ td->thread_hnd = Curl_thread_create(getaddrinfo_thread, &td->tsd);
+#else
+ td->thread_hnd = Curl_thread_create(gethostbyname_thread, &td->tsd);
+#endif
+
+ if(!td->thread_hnd) {
+#ifndef _WIN32_WCE
+ err = errno;
+#endif
+ goto err_exit;
+ }
+
+ return TRUE;
+
+ err_exit:
+ destroy_async_data(&conn->async);
+
+ SET_ERRNO(err);
+
+ return FALSE;
+}
+
+/*
+ * resolver_error() calls failf() with the appropriate message after a resolve
+ * error
+ */
+
+static CURLcode resolver_error(struct connectdata *conn)
+{
+ const char *host_or_proxy;
+ CURLcode rc;
+ if(conn->bits.httpproxy) {
+ host_or_proxy = "proxy";
+ rc = CURLE_COULDNT_RESOLVE_PROXY;
+ }
+ else {
+ host_or_proxy = "host";
+ rc = CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ failf(conn->data, "Could not resolve %s: %s", host_or_proxy,
+ conn->async.hostname);
+ return rc;
+}
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * This is the version for resolves-in-a-thread.
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ CURLcode rc = CURLE_OK;
+
+ DEBUGASSERT(conn && td);
+
+ /* wait for the thread to resolve the name */
+ if(Curl_thread_join(&td->thread_hnd))
+ rc = getaddrinfo_complete(conn);
+ else
+ DEBUGASSERT(0);
+
+ conn->async.done = TRUE;
+
+ if(entry)
+ *entry = conn->async.dns;
+
+ if(!conn->async.dns)
+ /* a name was not resolved, report error */
+ rc = resolver_error(conn);
+
+ destroy_async_data(&conn->async);
+
+ if(!conn->async.dns)
+ conn->bits.close = TRUE;
+
+ return (rc);
+}
+
+/*
+ * Curl_resolver_is_resolved() is called repeatedly to check if a previous
+ * name resolve request has completed. It should also make sure to time-out if
+ * the operation seems to take too long.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **entry)
+{
+ struct SessionHandle *data = conn->data;
+ struct thread_data *td = (struct thread_data*) conn->async.os_specific;
+ int done = 0;
+
+ *entry = NULL;
+
+ if(!td) {
+ DEBUGASSERT(td);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+
+ Curl_mutex_acquire(td->tsd.mtx);
+ done = td->tsd.done;
+ Curl_mutex_release(td->tsd.mtx);
+
+ if(done) {
+ getaddrinfo_complete(conn);
+
+ if(!conn->async.dns) {
+ CURLcode rc = resolver_error(conn);
+ destroy_async_data(&conn->async);
+ return rc;
+ }
+ destroy_async_data(&conn->async);
+ *entry = conn->async.dns;
+ }
+ else {
+ /* poll for name lookup done with exponential backoff up to 250ms */
+ long elapsed = Curl_tvdiff(Curl_tvnow(), data->progress.t_startsingle);
+ if(elapsed < 0)
+ elapsed = 0;
+
+ if(td->poll_interval == 0)
+ /* Start at 1ms poll interval */
+ td->poll_interval = 1;
+ else if(elapsed >= td->interval_end)
+ /* Back-off exponentially if last interval expired */
+ td->poll_interval *= 2;
+
+ if(td->poll_interval > 250)
+ td->poll_interval = 250;
+
+ td->interval_end = elapsed + td->poll_interval;
+ Curl_expire(conn->data, td->poll_interval);
+ }
+
+ return CURLE_OK;
+}
+
+int Curl_resolver_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return 0;
+}
+
+#ifndef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo() - for platforms without getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct in_addr in;
+
+ *waitp = 0; /* default to synchronous response */
+
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+ /* fire up a new resolver thread! */
+ if(init_resolve_thread(conn, hostname, port, NULL)) {
+ *waitp = 1; /* expect asynchronous response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ return Curl_ipv4_resolve_r(hostname, port);
+}
+
+#else /* !HAVE_GETADDRINFO */
+
+/*
+ * Curl_resolver_getaddrinfo() - for getaddrinfo
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints;
+ struct in_addr in;
+ Curl_addrinfo *res;
+ int error;
+ char sbuf[12];
+ int pf = PF_INET;
+#ifdef CURLRES_IPV6
+ struct in6_addr in6;
+#endif /* CURLRES_IPV6 */
+
+ *waitp = 0; /* default to synchronous response */
+
+ /* First check if this is an IPv4 address string */
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#ifdef CURLRES_IPV6
+ /* check if this is an IPv6 address string */
+ if(Curl_inet_pton (AF_INET6, hostname, &in6) > 0)
+ /* This is an IPv6 address literal */
+ return Curl_ip2addr(AF_INET6, &in6, hostname, port);
+
+ /*
+ * Check if a limited name resolve has been requested.
+ */
+ switch(conn->ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+
+ if((pf != PF_INET) && !Curl_ipv6works())
+ /* the stack seems to be a non-ipv6 one */
+ pf = PF_INET;
+
+#endif /* CURLRES_IPV6 */
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = conn->socktype;
+
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+
+ /* fire up a new resolver thread! */
+ if(init_resolve_thread(conn, hostname, port, &hints)) {
+ *waitp = 1; /* expect asynchronous response */
+ return NULL;
+ }
+
+ /* fall-back to blocking version */
+ infof(conn->data, "init_resolve_thread() failed for %s; %s\n",
+ hostname, Curl_strerror(conn, ERRNO));
+
+ error = Curl_getaddrinfo_ex(hostname, sbuf, &hints, &res);
+ if(error) {
+ infof(conn->data, "getaddrinfo() failed for %s:%d; %s\n",
+ hostname, port, Curl_strerror(conn, SOCKERRNO));
+ return NULL;
+ }
+ return res;
+}
+
+#endif /* !HAVE_GETADDRINFO */
+
+CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+ char *servers)
+{
+ (void)data;
+ (void)servers;
+ return CURLE_NOT_BUILT_IN;
+
+}
+
+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 */
diff --git a/libs/libcurl/src/asyn.h b/libs/libcurl/src/asyn.h
new file mode 100644
index 0000000000..1b681ea122
--- /dev/null
+++ b/libs/libcurl/src/asyn.h
@@ -0,0 +1,168 @@
+#ifndef HEADER_CURL_ASYN_H
+#define HEADER_CURL_ASYN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "curl_addrinfo.h"
+
+struct addrinfo;
+struct hostent;
+struct SessionHandle;
+struct connectdata;
+struct Curl_dns_entry;
+
+/*
+ * This header defines all functions in the internal asynch resolver interface.
+ * All asynch resolvers need to provide these functions.
+ * asyn-ares.c and asyn-thread.c are the current implementations of asynch
+ * resolver backends.
+ */
+
+/*
+ * Curl_resolver_global_init()
+ *
+ * Called from curl_global_init() to initialize global resolver environment.
+ * Returning anything else than CURLE_OK fails curl_global_init().
+ */
+int Curl_resolver_global_init(void);
+
+/*
+ * Curl_resolver_global_cleanup()
+ * Called from curl_global_cleanup() to destroy global resolver environment.
+ */
+void Curl_resolver_global_cleanup(void);
+
+/*
+ * Curl_resolver_init()
+ * Called from curl_easy_init() -> Curl_open() to initialize resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Should fill the passed pointer by the initialized handler.
+ * Returning anything else than CURLE_OK fails curl_easy_init() with the
+ * correspondent code.
+ */
+CURLcode Curl_resolver_init(void **resolver);
+
+/*
+ * Curl_resolver_cleanup()
+ * Called from curl_easy_cleanup() -> Curl_close() to cleanup resolver
+ * URL-state specific environment ('resolver' member of the UrlState
+ * structure). Should destroy the handler and free all resources connected to
+ * it.
+ */
+void Curl_resolver_cleanup(void *resolver);
+
+/*
+ * Curl_resolver_duphandle()
+ * Called from curl_easy_duphandle() to duplicate resolver URL-state specific
+ * environment ('resolver' member of the UrlState structure). Should
+ * duplicate the 'from' handle and pass the resulting handle to the 'to'
+ * pointer. Returning anything else than CURLE_OK causes failed
+ * curl_easy_duphandle() call.
+ */
+int Curl_resolver_duphandle(void **to, void *from);
+
+/*
+ * Curl_resolver_cancel().
+ *
+ * It is called from inside other functions to cancel currently performing
+ * resolver request. Should also free any temporary resources allocated to
+ * perform a request.
+ */
+void Curl_resolver_cancel(struct connectdata *conn);
+
+/* Curl_resolver_getsock()
+ *
+ * This function is called from the multi_getsock() function. 'sock' is a
+ * pointer to an array to hold the file descriptors, with 'numsock' being the
+ * size of that array (in number of entries). This function is supposed to
+ * return bitmask indicating what file descriptors (referring to array indexes
+ * in the 'sock' array) to wait for, read/write.
+ */
+int Curl_resolver_getsock(struct connectdata *conn, curl_socket_t *sock,
+ int numsocks);
+
+/*
+ * Curl_resolver_is_resolved()
+ *
+ * Called repeatedly to check if a previous name resolve request has
+ * completed. It should also make sure to time-out if the operation seems to
+ * take too long.
+ *
+ * Returns normal CURLcode errors.
+ */
+CURLcode Curl_resolver_is_resolved(struct connectdata *conn,
+ struct Curl_dns_entry **dns);
+
+/*
+ * Curl_resolver_wait_resolv()
+ *
+ * waits for a resolve to finish. This function should be avoided since using
+ * this risk getting the multi interface to "hang".
+ *
+ * If 'entry' is non-NULL, make it point to the resolved dns entry
+ *
+ * Returns CURLE_COULDNT_RESOLVE_HOST if the host was not resolved, and
+ * CURLE_OPERATION_TIMEDOUT if a time-out occurred.
+
+ */
+CURLcode Curl_resolver_wait_resolv(struct connectdata *conn,
+ struct Curl_dns_entry **dnsentry);
+
+/*
+ * Curl_resolver_getaddrinfo() - when using this resolver
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'hostent' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ *
+ * Each resolver backend must of course make sure to return data in the
+ * correct format to comply with this.
+ */
+Curl_addrinfo *Curl_resolver_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
+
+#ifndef CURLRES_ASYNCH
+/* convert these functions if an asynch resolver isn't used */
+#define Curl_resolver_cancel(x) Curl_nop_stmt
+#define Curl_resolver_is_resolved(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_wait_resolv(x,y) CURLE_COULDNT_RESOLVE_HOST
+#define Curl_resolver_getsock(x,y,z) 0
+#define Curl_resolver_duphandle(x,y) CURLE_OK
+#define Curl_resolver_init(x) CURLE_OK
+#define Curl_resolver_global_init() CURLE_OK
+#define Curl_resolver_global_cleanup() Curl_nop_stmt
+#define Curl_resolver_cleanup(x) Curl_nop_stmt
+#endif
+
+#ifdef CURLRES_ASYNCH
+#define Curl_resolver_asynch() 1
+#else
+#define Curl_resolver_asynch() 0
+#endif
+
+
+/********** end of generic resolver interface functions *****************/
+#endif /* HEADER_CURL_ASYN_H */
diff --git a/libs/libcurl/src/axtls.c b/libs/libcurl/src/axtls.c
new file mode 100644
index 0000000000..44e6b9303c
--- /dev/null
+++ b/libs/libcurl/src/axtls.c
@@ -0,0 +1,661 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, DirecTV
+ * contact: Eric Hu <ehu@directv.com>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all axTLS-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_AXTLS
+#include <axTLS/ssl.h>
+#include "axtls.h"
+
+#include "sendf.h"
+#include "inet_pton.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#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"
+
+
+/* Global axTLS init, called from Curl_ssl_init() */
+int Curl_axtls_init(void)
+{
+/* axTLS has no global init. Everything is done through SSL and SSL_CTX
+ * structs stored in connectdata structure. Perhaps can move to axtls.h.
+ */
+ return 1;
+}
+
+int Curl_axtls_cleanup(void)
+{
+ /* axTLS has no global cleanup. Perhaps can move this to axtls.h. */
+ return 1;
+}
+
+static CURLcode map_error_to_curl(int axtls_err)
+{
+ switch (axtls_err) {
+ case SSL_ERROR_NOT_SUPPORTED:
+ case SSL_ERROR_INVALID_VERSION:
+ case -70: /* protocol version alert from server */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ break;
+ case SSL_ERROR_NO_CIPHER:
+ return CURLE_SSL_CIPHER;
+ break;
+ case SSL_ERROR_BAD_CERTIFICATE: /* this may be bad server cert too */
+ case SSL_ERROR_NO_CERT_DEFINED:
+ case -42: /* bad certificate alert from server */
+ case -43: /* unsupported cert alert from server */
+ case -44: /* cert revoked alert from server */
+ case -45: /* cert expired alert from server */
+ case -46: /* cert unknown alert from server */
+ return CURLE_SSL_CERTPROBLEM;
+ break;
+ case SSL_X509_ERROR(X509_NOT_OK):
+ case SSL_X509_ERROR(X509_VFY_ERROR_NO_TRUSTED_CERT):
+ case SSL_X509_ERROR(X509_VFY_ERROR_BAD_SIGNATURE):
+ case SSL_X509_ERROR(X509_VFY_ERROR_NOT_YET_VALID):
+ case SSL_X509_ERROR(X509_VFY_ERROR_EXPIRED):
+ case SSL_X509_ERROR(X509_VFY_ERROR_SELF_SIGNED):
+ case SSL_X509_ERROR(X509_VFY_ERROR_INVALID_CHAIN):
+ case SSL_X509_ERROR(X509_VFY_ERROR_UNSUPPORTED_DIGEST):
+ case SSL_X509_ERROR(X509_INVALID_PRIV_KEY):
+ return CURLE_PEER_FAILED_VERIFICATION;
+ break;
+ case -48: /* unknown ca alert from server */
+ return CURLE_SSL_CACERT;
+ break;
+ case -49: /* access denied alert from server */
+ return CURLE_REMOTE_ACCESS_DENIED;
+ break;
+ case SSL_ERROR_CONN_LOST:
+ case SSL_ERROR_SOCK_SETUP_FAILURE:
+ case SSL_ERROR_INVALID_HANDSHAKE:
+ case SSL_ERROR_INVALID_PROT_MSG:
+ case SSL_ERROR_INVALID_HMAC:
+ case SSL_ERROR_INVALID_SESSION:
+ case SSL_ERROR_INVALID_KEY: /* it's too bad this doesn't map better */
+ case SSL_ERROR_FINISHED_INVALID:
+ case SSL_ERROR_NO_CLIENT_RENOG:
+ default:
+ return CURLE_SSL_CONNECT_ERROR;
+ break;
+ }
+}
+
+static Curl_recv axtls_recv;
+static Curl_send axtls_send;
+
+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 = 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;
+
+ /* 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
+ same connection */
+ return CURLE_OK;
+
+ /* axTLS only supports TLSv1 */
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(data->set.ssl.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ case CURL_SSLVERSION_TLSv1:
+ break;
+ default:
+ failf(data, "axTLS only supports TLSv1");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef AXTLSDEBUG
+ client_option |= SSL_DISPLAY_STATES | SSL_DISPLAY_RSA | SSL_DISPLAY_CERTS;
+#endif /* AXTLSDEBUG */
+
+ /* Allocate an SSL_CTX struct */
+ ssl_ctx = ssl_ctx_new(client_option, SSL_DEFAULT_CLNT_SESS);
+ if(ssl_ctx == NULL) {
+ failf(data, "unable to create client SSL context");
+ 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)
+ != SSL_OK) {
+ infof(data, "error reading ca cert file %s \n",
+ data->set.ssl.CAfile);
+ if(data->set.ssl.verifypeer) {
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+ else
+ infof(data, "found certificates in %s\n", data->set.ssl.CAfile);
+ }
+
+ /* gtls.c tasks we're skipping for now:
+ * 1) certificate revocation list checking
+ * 2) dns name assignment to host
+ * 3) set protocol priority. axTLS is TLSv1 only, so can probably ignore
+ * 4) set certificate priority. axTLS ignores type and sends certs in
+ * order added. can probably ignore this.
+ */
+
+ /* Load client certificate */
+ if(data->set.str[STRING_CERT]) {
+ i=0;
+ /* Instead of trying to analyze cert type here, let axTLS try them all. */
+ while(cert_types[i] != 0) {
+ ssl_fcn_return = ssl_obj_load(ssl_ctx, cert_types[i],
+ data->set.str[STRING_CERT], NULL);
+ if(ssl_fcn_return == SSL_OK) {
+ infof(data, "successfully read cert file %s \n",
+ data->set.str[STRING_CERT]);
+ break;
+ }
+ i++;
+ }
+ /* Tried all cert types, none worked. */
+ if(cert_types[i] == 0) {
+ failf(data, "%s is not x509 or pkcs12 format",
+ data->set.str[STRING_CERT]);
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load client key.
+ If a pkcs12 file successfully loaded a cert, then there's nothing to do
+ because the key has already been loaded. */
+ if(data->set.str[STRING_KEY] && cert_types[i] != SSL_OBJ_PKCS12) {
+ i=0;
+ /* Instead of trying to analyze key type here, let axTLS try them all. */
+ while(key_types[i] != 0) {
+ ssl_fcn_return = ssl_obj_load(ssl_ctx, key_types[i],
+ data->set.str[STRING_KEY], NULL);
+ if(ssl_fcn_return == SSL_OK) {
+ infof(data, "successfully read key file %s \n",
+ data->set.str[STRING_KEY]);
+ break;
+ }
+ i++;
+ }
+ /* Tried all key types, none worked. */
+ if(key_types[i] == 0) {
+ failf(data, "Failure: %s is not a supported key file",
+ data->set.str[STRING_KEY]);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* gtls.c does more here that is being left out for now
+ * 1) set session credentials. can probably ignore since axtls puts this
+ * info in the ssl_ctx struct
+ * 2) setting up callbacks. these seem gnutls specific
+ */
+
+ /* In axTLS, handshaking happens inside ssl_client_new. */
+ if(!Curl_ssl_getsessionid(conn, (void **) &ssl_sessionid, &ssl_idsize)) {
+ /* we got a session id, use it! */
+ infof (data, "SSL re-using session ID\n");
+ ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex],
+ ssl_sessionid, (uint8_t)ssl_idsize);
+ }
+ else
+ ssl = ssl_client_new(ssl_ctx, conn->sock[sockindex], NULL, 0);
+
+ conn->ssl[sockindex].ssl = ssl;
+ return CURLE_OK;
+}
+
+/*
+ * 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?
+ */
+
+ /* Verify server's certificate */
+ if(data->set.ssl.verifypeer) {
+ if(ssl_verify_cert(ssl) != SSL_OK) {
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "server cert verify failed");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ else
+ infof(data, "\t server certificate verification SKIPPED\n");
+
+ /* Here, gtls.c does issuer verification. axTLS has no straightforward
+ * equivalent, so omitting for now.*/
+
+ /* Here, gtls.c does the following
+ * 1) x509 hostname checking per RFC2818. axTLS doesn't support this, but
+ * it seems useful. This is now implemented, by Oscar Koeroo
+ * 2) checks cert validity based on time. axTLS does this in ssl_verify_cert
+ * 3) displays a bunch of cert information. axTLS doesn't support most of
+ * 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++) {
+ dns_altname = ssl_get_cert_subject_alt_dnsname(ssl, dns_altname_index);
+ if(dns_altname == NULL) {
+ break;
+ }
+ found_subject_alt_names = 1;
+
+ infof(data, "\tComparing subject alt name DNS with hostname: %s <-> %s\n",
+ dns_altname, conn->host.name);
+ if(Curl_cert_hostcheck(dns_altname, conn->host.name)) {
+ found_subject_alt_name_matching_conn = 1;
+ break;
+ }
+ }
+
+ /* 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);
+ 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) {
+ 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) {
+ /* Break connection ! */
+ Curl_axtls_close(conn, sockindex);
+ failf(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+ peer_CN, conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\tcommon name \"%s\" does not match \"%s\"\n",
+ peer_CN, conn->host.dispname);
+ }
+ }
+ }
+
+ /* General housekeeping */
+ conn->ssl[sockindex].state = ssl_connection_complete;
+ conn->recv[sockindex] = axtls_recv;
+ conn->send[sockindex] = axtls_send;
+
+ /* Put our freshly minted SSL session in cache */
+ ssl_idsize = ssl_get_session_id_size(ssl);
+ ssl_sessionid = ssl_get_session_id(ssl);
+ if(Curl_ssl_addsessionid(conn, (void *) ssl_sessionid, ssl_idsize)
+ != CURLE_OK)
+ infof (data, "failed to add session to cache\n");
+
+ 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,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *err)
+{
+ /* ssl_write() returns 'int' while write() and send() returns 'size_t' */
+ int rc = ssl_write(conn->ssl[sockindex].ssl, mem, (int)len);
+
+ infof(conn->data, " axtls_send\n");
+
+ if(rc < 0 ) {
+ *err = map_error_to_curl(rc);
+ rc = -1; /* generic error code for send failure */
+ }
+
+ *err = CURLE_OK;
+ return rc;
+}
+
+void Curl_axtls_close_all(struct SessionHandle *data)
+{
+ (void)data;
+ infof(data, " Curl_axtls_close_all\n");
+}
+
+void Curl_axtls_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ infof(conn->data, " Curl_axtls_close\n");
+
+ /* line from ssluse.c: (void)SSL_shutdown(connssl->ssl);
+ axTLS compat layer does nothing for SSL_shutdown */
+
+ /* The following line is from ssluse.c. There seems to be no axTLS
+ equivalent. ssl_free and ssl_ctx_free close things.
+ SSL_set_connect_state(connssl->handle); */
+
+ free_ssl_structs(connssl);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_axtls_shutdown(struct connectdata *conn, int sockindex)
+{
+ /* Outline taken from ssluse.c since functions are in axTLS compat layer.
+ axTLS's error set is much smaller, so a lot of error-handling was removed.
+ */
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct SessionHandle *data = conn->data;
+ uint8_t *buf;
+ ssize_t nread;
+
+ infof(conn->data, " Curl_axtls_shutdown\n");
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ /* axTLS compat layer does nothing for SSL_shutdown, so we do nothing too
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ (void)SSL_shutdown(connssl->ssl);
+ */
+
+ if(connssl->ssl) {
+ int what = Curl_socket_ready(conn->sock[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. 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");
+ retval = -1;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ }
+
+ free_ssl_structs(connssl);
+ }
+ return retval;
+}
+
+static ssize_t axtls_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *err)
+{
+ 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 = 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. */
+ Curl_axtls_close(conn, num);
+ }
+ else {
+ failf(conn->data, "axTLS recv error (%d)", ret);
+ *err = map_error_to_curl(ret);
+ ret = -1;
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_axtls_check_cxn(struct connectdata *conn)
+{
+ /* ssluse.c line: rc = SSL_peek(conn->ssl[FIRSTSOCKET].ssl, (void*)&buf, 1);
+ axTLS compat layer always returns the last argument, so connection is
+ always alive? */
+
+ infof(conn->data, " Curl_axtls_check_cxn\n");
+ return 1; /* connection still in place */
+}
+
+void Curl_axtls_session_free(void *ptr)
+{
+ (void)ptr;
+ /* free the ID */
+ /* both ssluse.c and gtls.c do something here, but axTLS's OpenSSL
+ compatibility layer does nothing, so we do nothing too. */
+}
+
+size_t Curl_axtls_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "axTLS/%s", ssl_version());
+}
+
+#endif /* USE_AXTLS */
diff --git a/libs/libcurl/src/axtls.h b/libs/libcurl/src/axtls.h
new file mode 100644
index 0000000000..db91365976
--- /dev/null
+++ b/libs/libcurl/src/axtls.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_AXTLS_H
+#define HEADER_CURL_AXTLS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, DirecTV
+ * contact: Eric Hu <ehu@directv.com>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_AXTLS
+#include "curl/curl.h"
+#include "urldata.h"
+
+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) */
+void Curl_axtls_close_all(struct SessionHandle *data);
+
+ /* close a SSL connection */
+void Curl_axtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_axtls_session_free(void *ptr);
+size_t Curl_axtls_version(char *buffer, size_t size);
+int Curl_axtls_shutdown(struct connectdata *conn, int sockindex);
+int Curl_axtls_check_cxn(struct connectdata *conn);
+
+/* API setup for axTLS */
+#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
+#define curlssl_shutdown(x,y) Curl_axtls_shutdown(x,y)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_axtls_version
+#define curlssl_check_cxn(x) Curl_axtls_check_cxn(x)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+
+#endif /* USE_AXTLS */
+#endif /* HEADER_CURL_AXTLS_H */
+
diff --git a/libs/libcurl/src/base64.c b/libs/libcurl/src/base64.c
new file mode 100644
index 0000000000..3f3f0f9b8b
--- /dev/null
+++ b/libs/libcurl/src/base64.c
@@ -0,0 +1,248 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* Base64 encoding/decoding */
+
+#include "curl_setup.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "urldata.h" /* for the SessionHandle definition */
+#include "warnless.h"
+#include "curl_base64.h"
+#include "curl_memory.h"
+#include "non-ascii.h"
+
+/* include memdebug.h last */
+#include "memdebug.h"
+
+/* ---- Base64 Encoding/Decoding Table --- */
+static const char table64[]=
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static void decodeQuantum(unsigned char *dest, const char *src)
+{
+ const char *s, *p;
+ unsigned long i, v, x = 0;
+
+ for(i = 0, s = src; i < 4; i++, s++) {
+ v = 0;
+ p = table64;
+ while(*p && (*p != *s)) {
+ v++;
+ p++;
+ }
+ if(*p == *s)
+ x = (x << 6) + v;
+ else if(*s == '=')
+ x = (x << 6);
+ }
+
+ dest[2] = curlx_ultouc(x & 0xFFUL);
+ x >>= 8;
+ dest[1] = curlx_ultouc(x & 0xFFUL);
+ x >>= 8;
+ dest[0] = curlx_ultouc(x & 0xFFUL);
+}
+
+/*
+ * Curl_base64_decode()
+ *
+ * Given a base64 NUL-terminated string at src, decode it and return a
+ * pointer in *outptr to a newly allocated memory area holding decoded
+ * data. Size of decoded data is returned in variable pointed by outlen.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When decoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen)
+{
+ size_t length = 0;
+ size_t equalsTerm = 0;
+ size_t i;
+ size_t numQuantums;
+ unsigned char lastQuantum[3];
+ size_t rawlen = 0;
+ unsigned char *newstr;
+
+ *outptr = NULL;
+ *outlen = 0;
+
+ while((src[length] != '=') && src[length])
+ length++;
+ /* A maximum of two = padding characters is allowed */
+ if(src[length] == '=') {
+ equalsTerm++;
+ if(src[length+equalsTerm] == '=')
+ equalsTerm++;
+ }
+ numQuantums = (length + equalsTerm) / 4;
+
+ /* Don't allocate a buffer if the decoded length is 0 */
+ if(numQuantums == 0)
+ return CURLE_OK;
+
+ rawlen = (numQuantums * 3) - equalsTerm;
+
+ /* The buffer must be large enough to make room for the last quantum
+ (which may be partially thrown out) and the zero terminator. */
+ newstr = malloc(rawlen+4);
+ if(!newstr)
+ return CURLE_OUT_OF_MEMORY;
+
+ *outptr = newstr;
+
+ /* Decode all but the last quantum (which may not decode to a
+ multiple of 3 bytes) */
+ for(i = 0; i < numQuantums - 1; i++) {
+ decodeQuantum(newstr, src);
+ newstr += 3; src += 4;
+ }
+
+ /* This final decode may actually read slightly past the end of the buffer
+ if the input string is missing pad bytes. This will almost always be
+ harmless. */
+ decodeQuantum(lastQuantum, src);
+ for(i = 0; i < 3 - equalsTerm; i++)
+ newstr[i] = lastQuantum[i];
+
+ newstr[i] = '\0'; /* zero terminate */
+
+ *outlen = rawlen; /* return size of decoded data */
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_base64_encode()
+ *
+ * Given a pointer to an input buffer and an input size, encode it and
+ * return a pointer in *outptr to a newly allocated memory area holding
+ * encoded data. Size of encoded data is returned in variable pointed by
+ * outlen.
+ *
+ * Input length of 0 indicates input buffer holds a NUL-terminated string.
+ *
+ * Returns CURLE_OK on success, otherwise specific error code. Function
+ * output shall not be considered valid unless CURLE_OK is returned.
+ *
+ * When encoded data length is 0, returns NULL in *outptr.
+ *
+ * @unittest: 1302
+ */
+CURLcode Curl_base64_encode(struct SessionHandle *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen)
+{
+ CURLcode error;
+ unsigned char ibuf[3];
+ unsigned char obuf[4];
+ int i;
+ int inputparts;
+ char *output;
+ char *base64data;
+ char *convbuf = NULL;
+
+ const char *indata = inputbuff;
+
+ *outptr = NULL;
+ *outlen = 0;
+
+ if(0 == insize)
+ insize = strlen(indata);
+
+ base64data = output = malloc(insize*4/3+4);
+ if(NULL == output)
+ return CURLE_OUT_OF_MEMORY;
+
+ /*
+ * The base64 data needs to be created using the network encoding
+ * not the host encoding. And we can't change the actual input
+ * so we copy it to a buffer, translate it, and use that instead.
+ */
+ error = Curl_convert_clone(data, indata, insize, &convbuf);
+ if(error) {
+ free(output);
+ return error;
+ }
+
+ if(convbuf)
+ indata = (char *)convbuf;
+
+ while(insize > 0) {
+ for(i = inputparts = 0; i < 3; i++) {
+ if(insize > 0) {
+ inputparts++;
+ ibuf[i] = (unsigned char) *indata;
+ indata++;
+ insize--;
+ }
+ else
+ ibuf[i] = 0;
+ }
+
+ obuf[0] = (unsigned char) ((ibuf[0] & 0xFC) >> 2);
+ obuf[1] = (unsigned char) (((ibuf[0] & 0x03) << 4) | \
+ ((ibuf[1] & 0xF0) >> 4));
+ obuf[2] = (unsigned char) (((ibuf[1] & 0x0F) << 2) | \
+ ((ibuf[2] & 0xC0) >> 6));
+ obuf[3] = (unsigned char) (ibuf[2] & 0x3F);
+
+ switch(inputparts) {
+ case 1: /* only one byte read */
+ snprintf(output, 5, "%c%c==",
+ table64[obuf[0]],
+ table64[obuf[1]]);
+ break;
+ case 2: /* two bytes read */
+ snprintf(output, 5, "%c%c%c=",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]]);
+ break;
+ default:
+ snprintf(output, 5, "%c%c%c%c",
+ table64[obuf[0]],
+ table64[obuf[1]],
+ table64[obuf[2]],
+ table64[obuf[3]] );
+ break;
+ }
+ output += 4;
+ }
+ *output = '\0';
+ *outptr = base64data; /* return pointer to new data, allocated memory */
+
+ if(convbuf)
+ free(convbuf);
+
+ *outlen = strlen(base64data); /* return the length of the new data */
+
+ return CURLE_OK;
+}
+/* ---- End of Base64 Encoding ---- */
diff --git a/libs/libcurl/src/bundles.c b/libs/libcurl/src/bundles.c
new file mode 100644
index 0000000000..aadf02656c
--- /dev/null
+++ b/libs/libcurl/src/bundles.c
@@ -0,0 +1,110 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2012, 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 <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "bundles.h"
+#include "sendf.h"
+#include "rawstr.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void conn_llist_dtor(void *user, void *element)
+{
+ struct connectdata *data = element;
+ (void)user;
+
+ data->bundle = NULL;
+}
+
+CURLcode Curl_bundle_create(struct SessionHandle *data,
+ struct connectbundle **cb_ptr)
+{
+ (void)data;
+ DEBUGASSERT(*cb_ptr == NULL);
+ *cb_ptr = malloc(sizeof(struct connectbundle));
+ if(!*cb_ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ (*cb_ptr)->num_connections = 0;
+ (*cb_ptr)->server_supports_pipelining = FALSE;
+
+ (*cb_ptr)->conn_list = Curl_llist_alloc((curl_llist_dtor) conn_llist_dtor);
+ if(!(*cb_ptr)->conn_list) {
+ Curl_safefree(*cb_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ return CURLE_OK;
+}
+
+void Curl_bundle_destroy(struct connectbundle *cb_ptr)
+{
+ if(!cb_ptr)
+ return;
+
+ if(cb_ptr->conn_list) {
+ Curl_llist_destroy(cb_ptr->conn_list, NULL);
+ cb_ptr->conn_list = NULL;
+ }
+ Curl_safefree(cb_ptr);
+}
+
+/* Add a connection to a bundle */
+CURLcode Curl_bundle_add_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn)
+{
+ if(!Curl_llist_insert_next(cb_ptr->conn_list, cb_ptr->conn_list->tail, conn))
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->bundle = cb_ptr;
+
+ cb_ptr->num_connections++;
+ return CURLE_OK;
+}
+
+/* Remove a connection from a bundle */
+int Curl_bundle_remove_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+
+ curr = cb_ptr->conn_list->head;
+ while(curr) {
+ if(curr->ptr == conn) {
+ Curl_llist_remove(cb_ptr->conn_list, curr, NULL);
+ cb_ptr->num_connections--;
+ conn->bundle = NULL;
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
+ }
+ return 0;
+}
diff --git a/libs/libcurl/src/bundles.h b/libs/libcurl/src/bundles.h
new file mode 100644
index 0000000000..3816c40655
--- /dev/null
+++ b/libs/libcurl/src/bundles.h
@@ -0,0 +1,45 @@
+#ifndef HEADER_CURL_BUNDLES_H
+#define HEADER_CURL_BUNDLES_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+struct connectbundle {
+ bool server_supports_pipelining; /* TRUE if server supports pipelining,
+ set after first response */
+ size_t num_connections; /* Number of connections in the bundle */
+ struct curl_llist *conn_list; /* The connectdata members of the bundle */
+};
+
+CURLcode Curl_bundle_create(struct SessionHandle *data,
+ struct connectbundle **cb_ptr);
+
+void Curl_bundle_destroy(struct connectbundle *cb_ptr);
+
+CURLcode Curl_bundle_add_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn);
+
+int Curl_bundle_remove_conn(struct connectbundle *cb_ptr,
+ struct connectdata *conn);
+
+
+#endif /* HEADER_CURL_BUNDLES_H */
+
diff --git a/libs/libcurl/src/checksrc.pl b/libs/libcurl/src/checksrc.pl
new file mode 100644
index 0000000000..9f5058ddb5
--- /dev/null
+++ b/libs/libcurl/src/checksrc.pl
@@ -0,0 +1,198 @@
+#!/usr/bin/perl
+#***************************************************************************
+# _ _ ____ _
+# Project ___| | | | _ \| |
+# / __| | | | |_) | |
+# | (__| |_| | _ <| |___
+# \___|\___/|_| \_\_____|
+#
+# Copyright (C) 2011, 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.
+#
+###########################################################################
+
+my $max_column = 79;
+my $indent = 2;
+
+my $warnings;
+my $errors;
+my $file;
+my $dir=".";
+my $wlist;
+
+sub checkwarn {
+ my ($num, $col, $file, $line, $msg, $error) = @_;
+
+ my $w=$error?"error":"warning";
+
+ if($w) {
+ $warnings++;
+ }
+ else {
+ $errors++;
+ }
+
+ $col++;
+ print "$file:$num:$col: $w: $msg\n";
+ print " $line\n";
+
+ if($col < 80) {
+ my $pref = (' ' x $col);
+ print "${pref}^\n";
+ }
+}
+
+$file = shift @ARGV;
+
+while(1) {
+
+ if($file =~ /-D(.*)/) {
+ $dir = $1;
+ $file = shift @ARGV;
+ next;
+ }
+ elsif($file =~ /-W(.*)/) {
+ $wlist .= " $1 ";
+ $file = shift @ARGV;
+ next;
+ }
+
+ last;
+}
+
+if(!$file) {
+ print "checksrc.pl [option] <file1> [file2] ...\n";
+ print " Options:\n";
+ print " -D[DIR] Directory to prepend file names\n";
+ print " -W[file] Whitelist the given file - ignore all its flaws\n";
+ exit;
+}
+
+do {
+ if("$wlist" !~ / $file /) {
+ my $fullname = $file;
+ $fullname = "$dir/$file" if ($fullname !~ '^\.?\.?/');
+ scanfile($fullname);
+ }
+ $file = shift @ARGV;
+
+} while($file);
+
+
+sub scanfile {
+ my ($file) = @_;
+
+ my $line = 1;
+ my $prevl;
+ my $l;
+ open(R, "<$file") || die "failed to open $file";
+
+ my $copyright=0;
+
+ while(<R>) {
+ chomp;
+ my $l = $_;
+ my $column = 0;
+
+ # check for a copyright statement
+ if(!$copyright && ($l =~ /copyright .* \d\d\d\d/i)) {
+ $copyright=1;
+ }
+
+ # detect long lines
+ if(length($l) > $max_column) {
+ checkwarn($line, length($l), $file, $l, "Longer than $max_column columns");
+ }
+ # detect TAB characters
+ if($l =~ /^(.*)\t/) {
+ checkwarn($line, length($1), $file, $l, "Contains TAB character", 1);
+ }
+ # detect trailing white space
+ if($l =~ /^(.*)[ \t]+\z/) {
+ checkwarn($line, length($1), $file, $l, "Trailing whitespace");
+ }
+
+ # check spaces after for/if/while
+ if($l =~ /^(.*)(for|if|while) \(/) {
+ if($1 =~ / *\#/) {
+ # this is a #if, treat it differently
+ }
+ else {
+ checkwarn($line, length($1)+length($2), $file, $l,
+ "$2 with space");
+ }
+ }
+
+ # check spaces after open paren after for/if/while
+ if($l =~ /^(.*)(for|if|while)\( /) {
+ if($1 =~ / *\#/) {
+ # this is a #if, treat it differently
+ }
+ else {
+ checkwarn($line, length($1)+length($2)+1, $file, $l,
+ "$2 with space first in condition");
+ }
+ }
+
+ # check for "} else"
+ if($l =~ /^(.*)\} *else/) {
+ checkwarn($line, length($1), $file, $l, "else after closing brace on same line");
+ }
+ # check for "){"
+ if($l =~ /^(.*)\)\{/) {
+ checkwarn($line, length($1)+1, $file, $l, "missing space after close paren");
+ }
+
+ # check for open brace first on line but not first column
+ # only alert if previous line ended with a close paren and wasn't a cpp
+ # line
+ if((($prevl =~ /\)\z/) && ($prevl !~ /^ *#/)) && ($l =~ /^( +)\{/)) {
+ checkwarn($line, length($1), $file, $l, "badly placed open brace");
+ }
+
+ # if the previous line starts with if/while/for AND ends with an open
+ # brace, check that this line is indented $indent more steps, if not
+ # a cpp line
+ if($prevl =~ /^( *)(if|while|for)\(.*\{\z/) {
+ my $first = length($1);
+
+ # this line has some character besides spaces
+ if(($l !~ /^ *#/) && ($l =~ /^( *)[^ ]/)) {
+ my $second = length($1);
+ my $expect = $first+$indent;
+ if($expect != $second) {
+ my $diff = $second - $first;
+ checkwarn($line, length($1), $file, $l,
+ "not indented $indent steps, uses $diff)");
+
+ }
+ }
+ }
+
+ $line++;
+ $prevl = $l;
+ }
+
+ if(!$copyright) {
+ checkwarn(1, 0, $file, "", "Missing copyright statement", 1);
+ }
+
+ close(R);
+
+}
+
+
+if($errors || $warnings) {
+ printf "checksrc: %d errors and %d warnings\n", $errors, $warnings;
+ exit 5; # return failure
+}
diff --git a/libs/libcurl/src/config-amigaos.h b/libs/libcurl/src/config-amigaos.h
new file mode 100644
index 0000000000..76d8877556
--- /dev/null
+++ b/libs/libcurl/src/config-amigaos.h
@@ -0,0 +1,167 @@
+#ifndef HEADER_CURL_CONFIG_AMIGAOS_H
+#define HEADER_CURL_CONFIG_AMIGAOS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for AmigaOS */
+/* ================================================================ */
+
+#ifdef __AMIGA__ /* Any AmigaOS flavour */
+
+#define HAVE_ARPA_INET_H 1
+#define HAVE_CLOSESOCKET_CAMEL 1
+#define HAVE_ERRNO_H 1
+#define HAVE_GETHOSTBYADDR 1
+#define HAVE_INET_ADDR 1
+#define HAVE_INTTYPES_H 1
+#define HAVE_IOCTLSOCKET_CAMEL 1
+#define HAVE_IOCTLSOCKET_CAMEL_FIONBIO 1
+#define HAVE_LIBCRYPTO 1
+#define HAVE_LIBSSL 1
+#define HAVE_LIBZ 1
+#define HAVE_LONGLONG 1
+#define HAVE_MALLOC_H 1
+#define HAVE_MEMORY_H 1
+#define HAVE_NETDB_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_NET_IF_H 1
+#define HAVE_OPENSSL_CRYPTO_H 1
+#define HAVE_OPENSSL_ERR_H 1
+#define HAVE_OPENSSL_PEM_H 1
+#define HAVE_OPENSSL_RSA_H 1
+#define HAVE_OPENSSL_SSL_H 1
+#define HAVE_OPENSSL_X509_H 1
+#define HAVE_PERROR 1
+#define HAVE_PWD_H 1
+#define HAVE_RAND_EGD 1
+#define HAVE_RAND_STATUS 1
+#define HAVE_SELECT 1
+#define HAVE_SETJMP_H 1
+#define HAVE_SGTTY_H 1
+#define HAVE_SIGNAL 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_SIG_ATOMIC_T 1
+#define HAVE_SOCKET 1
+#define HAVE_STRCASECMP 1
+#define HAVE_STRDUP 1
+#define HAVE_STRFTIME 1
+#define HAVE_STRICMP 1
+#define HAVE_STRINGS_H 1
+#define HAVE_STRING_H 1
+#define HAVE_STRSTR 1
+#define HAVE_STRUCT_TIMEVAL 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_SOCKIO_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_TIME_H 1
+#define HAVE_UNAME 1
+#define HAVE_UNISTD_H 1
+#define HAVE_UTIME 1
+#define HAVE_UTIME_H 1
+#define HAVE_WRITABLE_ARGV 1
+#define HAVE_ZLIB_H 1
+#define HAVE_SYS_IOCTL_H 1
+
+#define NEED_MALLOC_H 1
+
+#define SIZEOF_INT 4
+#define SIZEOF_SHORT 2
+#define SIZEOF_SIZE_T 4
+
+#define USE_MANUAL 1
+#define USE_OPENSSL 1
+#define USE_SSLEAY 1
+#define CURL_DISABLE_LDAP 1
+
+#define OS "AmigaOS"
+
+#define PACKAGE "curl"
+#define PACKAGE_BUGREPORT "curl-bug@haxx.se"
+#define PACKAGE_NAME "curl"
+#define PACKAGE_STRING "curl -"
+#define PACKAGE_TARNAME "curl"
+#define PACKAGE_VERSION "-"
+#define CURL_CA_BUNDLE "s:curl-ca-bundle.crt"
+
+#define RETSIGTYPE void
+#define SELECT_TYPE_ARG1 int
+#define SELECT_TYPE_ARG234 (fd_set *)
+#define SELECT_TYPE_ARG5 (struct timeval *)
+
+#define STDC_HEADERS 1
+#define TIME_WITH_SYS_TIME 1
+
+#define in_addr_t int
+
+#ifndef F_OK
+# define F_OK 0
+#endif
+
+#ifndef O_RDONLY
+# define O_RDONLY 0x0000
+#endif
+
+#ifndef LONG_MAX
+# define LONG_MAX 0x7fffffffL
+#endif
+
+#ifndef LONG_MIN
+# define LONG_MIN (-0x7fffffffL-1)
+#endif
+
+#define HAVE_GETNAMEINFO 1
+#define GETNAMEINFO_QUAL_ARG1 const
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+#define GETNAMEINFO_TYPE_ARG2 int
+#define GETNAMEINFO_TYPE_ARG46 size_t
+#define GETNAMEINFO_TYPE_ARG7 int
+
+#define HAVE_RECV 1
+#define RECV_TYPE_ARG1 long
+#define RECV_TYPE_ARG2 char *
+#define RECV_TYPE_ARG3 long
+#define RECV_TYPE_ARG4 long
+#define RECV_TYPE_RETV long
+
+#define HAVE_RECVFROM 1
+#define RECVFROM_TYPE_ARG1 long
+#define RECVFROM_TYPE_ARG2 char
+#define RECVFROM_TYPE_ARG3 long
+#define RECVFROM_TYPE_ARG4 long
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+#define RECVFROM_TYPE_ARG6 long
+#define RECVFROM_TYPE_RETV long
+
+#define HAVE_SEND 1
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 char *
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV int
+
+#endif /* __AMIGA__ */
+#endif /* HEADER_CURL_CONFIG_AMIGAOS_H */
diff --git a/libs/libcurl/src/config-dos.h b/libs/libcurl/src/config-dos.h
new file mode 100644
index 0000000000..cce5e81065
--- /dev/null
+++ b/libs/libcurl/src/config-dos.h
@@ -0,0 +1,188 @@
+#ifndef HEADER_CURL_CONFIG_DOS_H
+#define HEADER_CURL_CONFIG_DOS_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.
+ *
+ ***************************************************************************/
+
+
+/* ================================================================ */
+/* lib/config-dos.h - Hand crafted config file for DOS */
+/* ================================================================ */
+
+#if defined(DJGPP)
+ #define OS "MSDOS/djgpp"
+#elif defined(__HIGHC__)
+ #define OS "MSDOS/HighC"
+#elif defined(__WATCOMC__)
+ #define OS "MSDOS/Watcom"
+#else
+ #define OS "MSDOS/?"
+#endif
+
+#define PACKAGE "curl"
+
+#define HAVE_ARPA_INET_H 1
+#define HAVE_ERRNO_H 1
+#define HAVE_FCNTL_H 1
+#define HAVE_GETADDRINFO 1
+#define HAVE_GETNAMEINFO 1
+#define HAVE_GETPROTOBYNAME 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_IO_H 1
+#define HAVE_IOCTL 1
+#define HAVE_IOCTL_FIONBIO 1
+#define HAVE_IOCTLSOCKET 1
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+#define HAVE_LIMITS_H 1
+#define HAVE_LOCALE_H 1
+#define HAVE_LONGLONG 1
+#define HAVE_MEMORY_H 1
+#define HAVE_NETDB_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_NETINET_TCP_H 1
+#define HAVE_NET_IF_H 1
+#define HAVE_PROCESS_H 1
+#define HAVE_RECV 1
+#define HAVE_RECVFROM 1
+#define HAVE_SELECT 1
+#define HAVE_SEND 1
+#define HAVE_SETJMP_H 1
+#define HAVE_SETLOCALE 1
+#define HAVE_SETMODE 1
+#define HAVE_SIGNAL 1
+#define HAVE_SOCKET 1
+#define HAVE_SPNEGO 1
+#define HAVE_STRDUP 1
+#define HAVE_STRICMP 1
+#define HAVE_STRTOLL 1
+#define HAVE_STRUCT_TIMEVAL 1
+#define HAVE_STRUCT_IN6_ADDR 1
+#define HAVE_SYS_IOCTL_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_TIME_H 1
+#define HAVE_UNISTD_H 1
+
+#define NEED_MALLOC_H 1
+
+#define RETSIGTYPE void
+#define SIZEOF_INT 4
+#define SIZEOF_LONG_DOUBLE 16
+#define SIZEOF_SHORT 2
+#define SIZEOF_SIZE_T 4
+#define STDC_HEADERS 1
+#define TIME_WITH_SYS_TIME 1
+
+/* Qualifiers for send(), recv(), recvfrom() and getnameinfo(). */
+
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 void *
+#define SEND_TYPE_ARG3 int
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV int
+
+#define RECV_TYPE_ARG1 int
+#define RECV_TYPE_ARG2 void *
+#define RECV_TYPE_ARG3 int
+#define RECV_TYPE_ARG4 int
+#define RECV_TYPE_RETV int
+
+#define RECVFROM_TYPE_ARG1 int
+#define RECVFROM_TYPE_ARG2 void
+#define RECVFROM_TYPE_ARG3 int
+#define RECVFROM_TYPE_ARG4 int
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+#define RECVFROM_TYPE_ARG6 int
+#define RECVFROM_TYPE_RETV int
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+#define GETNAMEINFO_QUAL_ARG1 const
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+#define GETNAMEINFO_TYPE_ARG2 int
+#define GETNAMEINFO_TYPE_ARG46 int
+#define GETNAMEINFO_TYPE_ARG7 int
+
+#define BSD
+
+/* CURLDEBUG definition enables memory tracking */
+/* #define CURLDEBUG */
+
+/* USE_ZLIB on cmd-line */
+#ifdef USE_ZLIB
+ #define HAVE_ZLIB_H 1
+ #define HAVE_LIBZ 1
+#endif
+
+/* USE_SSLEAY on cmd-line */
+#ifdef USE_SSLEAY
+ #define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+ #define HAVE_OPENSSL_ENGINE_H 1
+ #define OPENSSL_NO_KRB5 1
+ #define USE_OPENSSL 1
+#endif
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+#define in_addr_t u_long
+
+#if defined(__HIGHC__) || \
+ (defined(__GNUC__) && (__GNUC__ < 4))
+ #define ssize_t int
+#endif
+
+#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
+
+/* Target HAVE_x section */
+
+#if defined(DJGPP)
+ #define HAVE_BASENAME 1
+ #define HAVE_STRCASECMP 1
+ #define HAVE_SIGACTION 1
+ #define HAVE_SIGSETJMP 1
+ #define HAVE_SYS_TIME_H 1
+ #define HAVE_TERMIOS_H 1
+ #define HAVE_VARIADIC_MACROS_GCC 1
+
+ /* Because djgpp <= 2.03 doesn't have snprintf() etc. */
+ #if (DJGPP_MINOR < 4)
+ #define _MPRINTF_REPLACE
+ #endif
+
+#elif defined(__WATCOMC__)
+ #define HAVE_STRCASECMP 1
+
+#elif defined(__HIGHC__)
+ #define HAVE_SYS_TIME_H 1
+ #define strerror(e) strerror_s_((e))
+#endif
+
+#ifdef MSDOS /* Watt-32 */
+ #define HAVE_CLOSE_S 1
+#endif
+
+#undef word
+#undef byte
+
+#endif /* HEADER_CURL_CONFIG_DOS_H */
+
diff --git a/libs/libcurl/src/config-mac.h b/libs/libcurl/src/config-mac.h
new file mode 100644
index 0000000000..d89c38515a
--- /dev/null
+++ b/libs/libcurl/src/config-mac.h
@@ -0,0 +1,126 @@
+#ifndef HEADER_CURL_CONFIG_MAC_H
+#define HEADER_CURL_CONFIG_MAC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* =================================================================== */
+/* Hand crafted config file for Mac OS 9 */
+/* =================================================================== */
+/* On Mac OS X you must run configure to generate curl_config.h file */
+/* =================================================================== */
+
+#define OS "mac"
+
+/* Define if you want the built-in manual */
+#define USE_MANUAL 1
+
+#define HAVE_ERRNO_H 1
+#define HAVE_NETINET_IN_H 1
+#define HAVE_SYS_SOCKET_H 1
+#define HAVE_SYS_SELECT_H 1
+#define HAVE_NETDB_H 1
+#define HAVE_ARPA_INET_H 1
+#define HAVE_UNISTD_H 1
+#define HAVE_NET_IF_H 1
+#define HAVE_SYS_TYPES_H 1
+#define HAVE_GETTIMEOFDAY 1
+#define HAVE_FCNTL_H 1
+#define HAVE_SYS_STAT_H 1
+#define HAVE_ALLOCA_H 1
+#define HAVE_STDLIB_H 1
+#define HAVE_TIME_H 1
+#define HAVE_UTIME_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_UTIME_H 1
+
+#define TIME_WITH_SYS_TIME 1
+
+#define HAVE_ALARM 1
+#define HAVE_FTRUNCATE 1
+#define HAVE_UTIME 1
+#define HAVE_SETVBUF 1
+#define HAVE_STRFTIME 1
+#define HAVE_INET_ADDR 1
+#define HAVE_MEMCPY 1
+#define HAVE_SELECT 1
+#define HAVE_SOCKET 1
+#define HAVE_STRUCT_TIMEVAL 1
+
+#define HAVE_SIGACTION 1
+#define HAVE_SIGNAL_H 1
+#define HAVE_SIG_ATOMIC_T 1
+
+#ifdef MACOS_SSL_SUPPORT
+# define USE_SSLEAY 1
+# define USE_OPENSSL 1
+#endif
+
+#define CURL_DISABLE_LDAP 1
+
+#define HAVE_RAND_STATUS 1
+#define HAVE_RAND_EGD 1
+
+#define HAVE_IOCTL 1
+#define HAVE_IOCTL_FIONBIO 1
+
+#define RETSIGTYPE void
+
+#define SIZEOF_INT 4
+#define SIZEOF_SHORT 2
+#define SIZEOF_SIZE_T 4
+
+#define HAVE_GETNAMEINFO 1
+#define GETNAMEINFO_QUAL_ARG1 const
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+#define GETNAMEINFO_TYPE_ARG46 size_t
+#define GETNAMEINFO_TYPE_ARG7 int
+
+#define HAVE_RECV 1
+#define RECV_TYPE_ARG1 int
+#define RECV_TYPE_ARG2 void *
+#define RECV_TYPE_ARG3 size_t
+#define RECV_TYPE_ARG4 int
+#define RECV_TYPE_RETV ssize_t
+
+#define HAVE_RECVFROM 1
+#define RECVFROM_TYPE_ARG1 int
+#define RECVFROM_TYPE_ARG2 void
+#define RECVFROM_TYPE_ARG3 size_t
+#define RECVFROM_TYPE_ARG4 int
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+#define RECVFROM_TYPE_ARG6 int
+#define RECVFROM_TYPE_RETV ssize_t
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+#define HAVE_SEND 1
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 void *
+#define SEND_TYPE_ARG3 size_T
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV ssize_t
+
+#define HAVE_EXTRA_STRICMP_H 1
+#define HAVE_EXTRA_STRDUP_H 1
+
+#endif /* HEADER_CURL_CONFIG_MAC_H */
diff --git a/libs/libcurl/src/config-os400.h b/libs/libcurl/src/config-os400.h
new file mode 100644
index 0000000000..a290fe43d7
--- /dev/null
+++ b/libs/libcurl/src/config-os400.h
@@ -0,0 +1,551 @@
+#ifndef HEADER_CURL_CONFIG_OS400_H
+#define HEADER_CURL_CONFIG_OS400_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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for OS/400 */
+/* ================================================================ */
+
+#pragma enum(int)
+
+#undef PACKAGE
+
+/* Version number of this archive. */
+#undef VERSION
+
+/* Define if you have the getpass function. */
+#undef HAVE_GETPASS
+
+/* Define cpu-machine-OS */
+#define OS "OS/400"
+
+/* Define if you have the gethostbyaddr_r() function with 5 arguments */
+#define HAVE_GETHOSTBYADDR_R_5
+
+/* Define if you have the gethostbyaddr_r() function with 7 arguments */
+#undef HAVE_GETHOSTBYADDR_R_7
+
+/* Define if you have the gethostbyaddr_r() function with 8 arguments */
+#undef HAVE_GETHOSTBYADDR_R_8
+
+/* OS400 supports a 3-argument ASCII version of gethostbyaddr_r(), but its
+ * prototype is incompatible with the "standard" one (1st argument is not
+ * const). However, getaddrinfo() is supported (ASCII version defined as
+ * a local wrapper in setup-os400.h) in a threadsafe way: we can then
+ * configure getaddrinfo() as such and get rid of gethostbyname_r() without
+ * loss of threadsafeness. */
+#undef HAVE_GETHOSTBYNAME_R
+#undef HAVE_GETHOSTBYNAME_R_3
+#undef HAVE_GETHOSTBYNAME_R_5
+#undef HAVE_GETHOSTBYNAME_R_6
+#define HAVE_GETADDRINFO
+#define HAVE_GETADDRINFO_THREADSAFE
+
+/* Define if you need the _REENTRANT define for some functions */
+#undef NEED_REENTRANT
+
+/* Define if you have the Kerberos4 libraries (including -ldes) */
+#undef HAVE_KRB4
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define this to 'int' if ssize_t is not an available typedefed type */
+#undef ssize_t
+
+/* Define this as a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define this to your Entropy Gathering Daemon socket pathname */
+#undef EGD_SOCKET
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define if you have the <alloca.h> header file. */
+#undef HAVE_ALLOCA_H
+
+/* Define if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H
+
+/* Define if you have the `closesocket' function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define if you have the <crypto.h> header file. */
+#undef HAVE_CRYPTO_H
+
+/* Define if you have the <des.h> header file. */
+#undef HAVE_DES_H
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H
+
+/* Define if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H
+
+/* Define if you have the `geteuid' function. */
+#define HAVE_GETEUID
+
+/* Define if you have the `gethostbyaddr' function. */
+#define HAVE_GETHOSTBYADDR
+
+/* Define if you have the `gethostbyaddr_r' function. */
+#define HAVE_GETHOSTBYADDR_R
+
+/* Define if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME
+
+/* Define if you have the <getopt.h> header file. */
+#undef HAVE_GETOPT_H
+
+/* Define if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define if you have the `getpwuid' function. */
+#define HAVE_GETPWUID
+
+/* Define if you have the `getservbyname' function. */
+#define HAVE_GETSERVBYNAME
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY
+
+/* Define if you have the `timeval' struct. */
+#define HAVE_STRUCT_TIMEVAL
+
+/* Define if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR
+
+/* Define if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H
+
+/* Define if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define if you have the `krb_get_our_ip_for_realm' function. */
+#undef HAVE_KRB_GET_OUR_IP_FOR_REALM
+
+/* Define if you have the <krb.h> header file. */
+#undef HAVE_KRB_H
+
+/* Define if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the `resolve' library (-lresolve). */
+#undef HAVE_LIBRESOLVE
+
+/* Define if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define if you have GSS API. */
+#define HAVE_GSSAPI
+
+/* Define if you have the `ucb' library (-lucb). */
+#undef HAVE_LIBUCB
+
+/* Define if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H
+
+/* Define if you need the malloc.h header file even with stdlib.h */
+/* #define NEED_MALLOC_H 1 */
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H
+
+/* Define if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H
+
+/* Define if you have the <openssl/crypto.h> header file. */
+#undef HAVE_OPENSSL_CRYPTO_H
+
+/* Define if you have the <openssl/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H
+
+/* Define if you have the <openssl/pem.h> header file. */
+#undef HAVE_OPENSSL_PEM_H
+
+/* Define if you have the <openssl/rsa.h> header file. */
+#undef HAVE_OPENSSL_RSA_H
+
+/* Define if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define if you have the <openssl/x509.h> header file. */
+#undef HAVE_OPENSSL_X509_H
+
+/* Define if you have the <pem.h> header file. */
+#undef HAVE_PEM_H
+
+/* Define if you have the `perror' function. */
+#define HAVE_PERROR
+
+/* Define if you have the <pwd.h> header file. */
+#define HAVE_PWD_H
+
+/* Define if you have the `RAND_egd' function. */
+#undef HAVE_RAND_EGD
+
+/* Define if you have the `RAND_screen' function. */
+#undef HAVE_RAND_SCREEN
+
+/* Define if you have the `RAND_status' function. */
+#undef HAVE_RAND_STATUS
+
+/* Define if you have the <rsa.h> header file. */
+#undef HAVE_RSA_H
+
+/* Define if you have the `select' function. */
+#define HAVE_SELECT
+
+/* Define if you have the `setvbuf' function. */
+#define HAVE_SETVBUF
+
+/* Define if you have the <sgtty.h> header file. */
+#undef HAVE_SGTTY_H
+
+/* Define if you have the `sigaction' function. */
+#define HAVE_SIGACTION
+
+/* Define if you have the `signal' function. */
+#undef HAVE_SIGNAL
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T
+
+/* Define if sig_atomic_t is already defined as volatile. */
+#undef HAVE_SIG_ATOMIC_T_VOLATILE
+
+/* Define if you have the `socket' function. */
+#define HAVE_SOCKET
+
+/* Define if you have the <ssl.h> header file. */
+#undef HAVE_SSL_H
+
+/* Define if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* 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. */
+#define HAVE_STRCMPI
+
+/* Define if you have the `stricmp' function. */
+#define HAVE_STRICMP
+
+/* Define if you have the `strdup' function. */
+#define HAVE_STRDUP
+
+
+/* Define if you have the `strftime' function. */
+#define HAVE_STRFTIME
+
+/* Define if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define if you have the <stropts.h> header file. */
+#undef HAVE_STROPTS_H
+
+/* Define if you have the `strstr' function. */
+#define HAVE_STRSTR
+
+/* Define if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R
+
+/* Define if you have the `strtoll' function. */
+#undef HAVE_STRTOLL /* Allows ASCII compile on V5R1. */
+
+/* Define if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H
+
+/* Define if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H
+
+/* Define if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H
+
+/* Define if you have the `tcgetattr' function. */
+#undef HAVE_TCGETATTR
+
+/* Define if you have the `tcsetattr' function. */
+#undef HAVE_TCSETATTR
+
+/* Define if you have the <termios.h> header file. */
+#undef HAVE_TERMIOS_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H
+
+/* Define if you have the `uname' function. */
+#undef HAVE_UNAME
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H
+
+/* Define if you have the <winsock.h> header file. */
+#undef HAVE_WINSOCK_H
+
+/* Define if you have the <x509.h> header file. */
+#undef HAVE_X509_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of a `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 8
+
+/* Define if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG
+
+/* The size of a `long long', as computed by sizeof. */
+#define SIZEOF_LONG_LONG 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* Whether long long constants must be suffixed by LL. */
+
+#define HAVE_LL
+
+/* Define this if you have struct sockaddr_storage */
+#define HAVE_STRUCT_SOCKADDR_STORAGE
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#define _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* type to use in place of in_addr_t if not defined */
+#define in_addr_t unsigned long
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define if you have the ioctl function. */
+#define HAVE_IOCTL
+
+/* Define if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO
+
+/* Define if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR
+
+/* To disable LDAP */
+#undef CURL_DISABLE_LDAP
+
+/* Definition to make a library symbol externally visible. */
+#define CURL_EXTERN_SYMBOL
+
+/* Define if you have the ldap_url_parse procedure. */
+/* #define HAVE_LDAP_URL_PARSE */ /* Disabled because of an IBM bug. */
+
+/* Define if you have the getnameinfo function. */
+/* OS400 has no ASCII version of this procedure: wrapped in setup-os400.h. */
+#define HAVE_GETNAMEINFO
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 socklen_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the recvfrom function. */
+#define HAVE_RECVFROM
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* 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"
+
+/* ---------------------------------------------------------------- */
+/* ADDITIONAL DEFINITIONS */
+/* ---------------------------------------------------------------- */
+
+/* The following must be defined BEFORE system header files inclusion. */
+
+#define __ptr128 /* No teraspace. */
+#define qadrt_use_fputc_inline /* Generate fputc() wrapper inline. */
+#define qadrt_use_fread_inline /* Generate fread() wrapper inline. */
+#define qadrt_use_fwrite_inline /* Generate fwrite() wrapper inline. */
+
+#endif /* HEADER_CURL_CONFIG_OS400_H */
diff --git a/libs/libcurl/src/config-riscos.h b/libs/libcurl/src/config-riscos.h
new file mode 100644
index 0000000000..e400577895
--- /dev/null
+++ b/libs/libcurl/src/config-riscos.h
@@ -0,0 +1,513 @@
+#ifndef HEADER_CURL_CONFIG_RISCOS_H
+#define HEADER_CURL_CONFIG_RISCOS_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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for RISC OS */
+/* ================================================================ */
+
+/* Name of this package! */
+#undef PACKAGE
+
+/* Version number of this archive. */
+#undef VERSION
+
+/* Define if you have the getpass function. */
+#undef HAVE_GETPASS
+
+/* Define cpu-machine-OS */
+#define OS "ARM-RISC OS"
+
+/* Define if you want the built-in manual */
+#define USE_MANUAL
+
+/* Define if you have the gethostbyaddr_r() function with 5 arguments */
+#undef HAVE_GETHOSTBYADDR_R_5
+
+/* Define if you have the gethostbyaddr_r() function with 7 arguments */
+#undef HAVE_GETHOSTBYADDR_R_7
+
+/* Define if you have the gethostbyaddr_r() function with 8 arguments */
+#undef HAVE_GETHOSTBYADDR_R_8
+
+/* Define if you have the gethostbyname_r() function with 3 arguments */
+#undef HAVE_GETHOSTBYNAME_R_3
+
+/* Define if you have the gethostbyname_r() function with 5 arguments */
+#undef HAVE_GETHOSTBYNAME_R_5
+
+/* Define if you have the gethostbyname_r() function with 6 arguments */
+#undef HAVE_GETHOSTBYNAME_R_6
+
+/* Define if you need the _REENTRANT define for some functions */
+#undef NEED_REENTRANT
+
+/* Define if you have the Kerberos4 libraries (including -ldes) */
+#undef HAVE_KRB4
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define this to 'int' if ssize_t is not an available typedefed type */
+#undef ssize_t
+
+/* Define this as a suitable file to read random data from */
+#undef RANDOM_FILE
+
+/* Define this to your Entropy Gathering Daemon socket pathname */
+#undef EGD_SOCKET
+
+/* Define if you want to enable IPv6 support */
+#undef ENABLE_IPV6
+
+/* Define if you have the alarm function. */
+#define HAVE_ALARM
+
+/* Define if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H
+
+/* Define if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H
+
+/* Define if you have the `closesocket' function. */
+#undef HAVE_CLOSESOCKET
+
+/* Define if you have the <crypto.h> header file. */
+#undef HAVE_CRYPTO_H
+
+/* Define if you have the <des.h> header file. */
+#undef HAVE_DES_H
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H
+
+/* Define if you have the <err.h> header file. */
+#undef HAVE_ERR_H
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H
+
+/* Define if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE
+
+/* Define if getaddrinfo exists and works */
+#define HAVE_GETADDRINFO
+
+/* Define if you have the `geteuid' function. */
+#undef HAVE_GETEUID
+
+/* Define if you have the `gethostbyaddr' function. */
+#define HAVE_GETHOSTBYADDR
+
+/* Define if you have the `gethostbyaddr_r' function. */
+#undef HAVE_GETHOSTBYADDR_R
+
+/* Define if you have the `gethostbyname_r' function. */
+#undef HAVE_GETHOSTBYNAME_R
+
+/* Define if you have the `gethostname' function. */
+#define HAVE_GETHOSTNAME
+
+/* Define if you have the <getopt.h> header file. */
+#define HAVE_GETOPT_H
+
+/* Define if you have the `getpass_r' function. */
+#undef HAVE_GETPASS_R
+
+/* Define if you have the `getpwuid' function. */
+#undef HAVE_GETPWUID
+
+/* Define if you have the `getservbyname' function. */
+#undef HAVE_GETSERVBYNAME
+
+/* Define if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY
+
+/* Define if you have the `timeval' struct. */
+#define HAVE_STRUCT_TIMEVAL
+
+/* Define if you have the `inet_addr' function. */
+#undef HAVE_INET_ADDR
+
+/* Define if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H
+
+/* Define if you have the <io.h> header file. */
+#undef HAVE_IO_H
+
+/* Define if you have the `krb_get_our_ip_for_realm' function. */
+#undef HAVE_KRB_GET_OUR_IP_FOR_REALM
+
+/* Define if you have the <krb.h> header file. */
+#undef HAVE_KRB_H
+
+/* Define if you have the `crypto' library (-lcrypto). */
+#undef HAVE_LIBCRYPTO
+
+/* Define if you have the `nsl' library (-lnsl). */
+#undef HAVE_LIBNSL
+
+/* Define if you have the `resolv' library (-lresolv). */
+#undef HAVE_LIBRESOLV
+
+/* Define if you have the `resolve' library (-lresolve). */
+#undef HAVE_LIBRESOLVE
+
+/* Define if you have the `socket' library (-lsocket). */
+#undef HAVE_LIBSOCKET
+
+/* Define if you have the `ssl' library (-lssl). */
+#undef HAVE_LIBSSL
+
+/* Define if you have the `ucb' library (-lucb). */
+#undef HAVE_LIBUCB
+
+/* Define if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define if you have the <malloc.h> header file. */
+#define HAVE_MALLOC_H
+
+/* Define if you need the malloc.h header file even with stdlib.h */
+/* #define NEED_MALLOC_H 1 */
+
+/* Define if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H
+
+/* Define if you have the <netinet/if_ether.h> header file. */
+#undef HAVE_NETINET_IF_ETHER_H
+
+/* Define if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H
+
+/* Define if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H
+
+/* Define if you have the <openssl/crypto.h> header file. */
+#undef HAVE_OPENSSL_CRYPTO_H
+
+/* Define if you have the <openssl/err.h> header file. */
+#undef HAVE_OPENSSL_ERR_H
+
+/* Define if you have the <openssl/pem.h> header file. */
+#undef HAVE_OPENSSL_PEM_H
+
+/* Define if you have the <openssl/rsa.h> header file. */
+#undef HAVE_OPENSSL_RSA_H
+
+/* Define if you have the <openssl/ssl.h> header file. */
+#undef HAVE_OPENSSL_SSL_H
+
+/* Define if you have the <openssl/x509.h> header file. */
+#undef HAVE_OPENSSL_X509_H
+
+/* Define if you have the <pem.h> header file. */
+#undef HAVE_PEM_H
+
+/* Define if you have the `perror' function. */
+#undef HAVE_PERROR
+
+/* Define if you have the <pwd.h> header file. */
+#undef HAVE_PWD_H
+
+/* Define if you have the `RAND_egd' function. */
+#undef HAVE_RAND_EGD
+
+/* Define if you have the `RAND_screen' function. */
+#undef HAVE_RAND_SCREEN
+
+/* Define if you have the `RAND_status' function. */
+#undef HAVE_RAND_STATUS
+
+/* Define if you have the <rsa.h> header file. */
+#undef HAVE_RSA_H
+
+/* Define if you have the `select' function. */
+#define HAVE_SELECT
+
+/* Define if you have the `setvbuf' function. */
+#undef HAVE_SETVBUF
+
+/* Define if you have the <sgtty.h> header file. */
+#define HAVE_SGTTY_H
+
+/* Define if you have the `sigaction' function. */
+#undef HAVE_SIGACTION
+
+/* Define if you have the `signal' function. */
+#define HAVE_SIGNAL
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T
+
+/* Define if sig_atomic_t is already defined as volatile. */
+#undef HAVE_SIG_ATOMIC_T_VOLATILE
+
+/* Define if you have the `socket' function. */
+#define HAVE_SOCKET
+
+/* Define if you have the <ssl.h> header file. */
+#undef HAVE_SSL_H
+
+/* Define if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H
+
+/* Define if you have the `strcasecmp' function. */
+#undef HAVE_STRCASECMP
+
+/* Define if you have the `strcmpi' function. */
+#undef HAVE_STRCMPI
+
+/* Define if you have the `strdup' function. */
+#define HAVE_STRDUP
+
+/* Define if you have the `strftime' function. */
+#define HAVE_STRFTIME
+
+/* Define if you have the `stricmp' function. */
+#define HAVE_STRICMP
+
+/* Define if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define if you have the <string.h> header file. */
+#define HAVE_STRING_H
+
+/* Define if you have the `strlcpy' function. */
+#undef HAVE_STRLCPY
+
+/* Define if you have the `strstr' function. */
+#define HAVE_STRSTR
+
+/* Define if you have the `strtok_r' function. */
+#undef HAVE_STRTOK_R
+
+/* Define if you have the `strtoll' function. */
+#undef HAVE_STRTOLL
+
+/* Define if you have the <sys/param.h> header file. */
+#undef HAVE_SYS_PARAM_H
+
+/* Define if you have the <sys/select.h> header file. */
+#undef HAVE_SYS_SELECT_H
+
+/* Define if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H
+
+/* Define if you have the <sys/sockio.h> header file. */
+#undef HAVE_SYS_SOCKIO_H
+
+/* Define if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H
+
+/* Define if you have the `tcgetattr' function. */
+#define HAVE_TCGETATTR
+
+/* Define if you have the `tcsetattr' function. */
+#define HAVE_TCSETATTR
+
+/* Define if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H
+
+/* Define if you have the <termio.h> header file. */
+#undef HAVE_TERMIO_H
+
+/* Define if you have the <time.h> header file. */
+#undef HAVE_TIME_H
+
+/* Define if you have the `uname' function. */
+#define HAVE_UNAME
+
+/* Define if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H
+
+/* Define if you have the <winsock.h> header file. */
+#undef HAVE_WINSOCK_H
+
+/* Define if you have the <x509.h> header file. */
+#undef HAVE_X509_H
+
+/* Name of package */
+#undef PACKAGE
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long double', as computed by sizeof. */
+#undef SIZEOF_LONG_DOUBLE
+
+/* The size of `long long', as computed by sizeof. */
+#undef SIZEOF_LONG_LONG
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+#undef TIME_WITH_SYS_TIME
+
+/* Version number of package */
+#undef VERSION
+
+/* Define if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#undef _FILE_OFFSET_BITS
+
+/* Define for large files, on AIX-style hosts. */
+#undef _LARGE_FILES
+
+/* Define to empty if `const' does not conform to ANSI C. */
+#undef const
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+#undef size_t
+
+/* Define to `int' if <sys/types.h> does not define. */
+#undef ssize_t
+
+/* Define if you have the ioctl function. */
+#define HAVE_IOCTL
+
+/* Define if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP
+
+/* Define if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV ssize_t
+
+/* Define 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV ssize_t
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV ssize_t
+
+#endif /* HEADER_CURL_CONFIG_RISCOS_H */
diff --git a/libs/libcurl/src/config-symbian.h b/libs/libcurl/src/config-symbian.h
new file mode 100644
index 0000000000..17d92b0619
--- /dev/null
+++ b/libs/libcurl/src/config-symbian.h
@@ -0,0 +1,818 @@
+#ifndef HEADER_CURL_CONFIG_SYMBIAN_H
+#define HEADER_CURL_CONFIG_SYMBIAN_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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for Symbian */
+/* ================================================================ */
+
+/* Location of default ca bundle */
+/* #define CURL_CA_BUNDLE "/etc/pki/tls/certs/ca-bundle.crt"*/
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #define CURL_DISABLE_VERBOSE_STRINGS 1*/
+
+/* Definition to make a library symbol externally visible. */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* Use Windows LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define to 1 if you have the <alloca.h> header file. */
+/*#define HAVE_ALLOCA_H 1*/
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+/*#define HAVE_ARPA_TFTP_H 1*/
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+/*#define HAVE_BASENAME 1*/
+
+/* Define to 1 if bool is an available type. */
+/*#define HAVE_BOOL_T 1*/
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/*#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1*/
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/*#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1*/
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the `fork' function. */
+/*#define HAVE_FORK 1*/
+
+/* Define to 1 if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if getaddrinfo exists and works */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `gethostbyaddr' function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* If you have gethostbyname */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+/*#define HAVE_GETRLIMIT 1*/
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* we have a glibc-style strerror_r() */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/*#define HAVE_IDNA_STRERROR 1*/
+
+/* Define to 1 if you have the `idn_free' function. */
+/*#define HAVE_IDN_FREE 1*/
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/*#define HAVE_IDN_FREE_H 1*/
+
+/* Define to 1 if you have the `inet_addr' function. */
+/*#define HAVE_INET_ADDR 1*/
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+/*#define HAVE_INET_NTOP 1*/
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+/*#define HAVE_INET_PTON 1*/
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/*#define HAVE_LBER_H 1*/
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/*#define HAVE_LDAP_H 1*/
+
+/* Use LDAPS implementation */
+/*#define HAVE_LDAP_SSL 1*/
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/*#define HAVE_LDAP_URL_PARSE 1*/
+
+/* Define to 1 if you have the <libgen.h> header file. */
+/*#define HAVE_LIBGEN_H 1*/
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/*#define HAVE_LIBIDN 1*/
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/*#define HAVE_LIBSSH2 1*/
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/*#define HAVE_LIBSSH2_H 1*/
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/*#define HAVE_LIBSSL 1*/
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+/*#define HAVE_MALLOC_H 1*/
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/*#define HAVE_MSG_NOSIGNAL 1*/
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+/*#define HAVE_NETINET_TCP_H 1*/
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/*#define HAVE_NI_WITHSCOPEID 1*/
+
+/* we have no strerror_r() proto */
+/* #undef HAVE_NO_STRERROR_R_DECL */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+ */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/*#define HAVE_OPENSSL_CRYPTO_H 1*/
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/*#define HAVE_OPENSSL_ENGINE_H 1*/
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/*#define HAVE_OPENSSL_ERR_H 1*/
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/*#define HAVE_OPENSSL_PEM_H 1*/
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/*#define HAVE_OPENSSL_PKCS12_H 1*/
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/*#define HAVE_OPENSSL_RSA_H 1*/
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/*#define HAVE_OPENSSL_SSL_H 1*/
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/*#define HAVE_OPENSSL_X509_H 1*/
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* Define to 1 if you have the `poll' function. */
+/*#define HAVE_POLL 1*/
+
+/* If you have a fine poll */
+/*#define HAVE_POLL_FINE 1*/
+
+/* Define to 1 if you have the <poll.h> header file. */
+/*#define HAVE_POLL_H 1*/
+
+/* we have a POSIX-style strerror_r() */
+#define HAVE_POSIX_STRERROR_R 1
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+#define HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/*#define HAVE_RAND_STATUS 1*/
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+/* #undef HAVE_SETMODE */
+
+/* Define to 1 if you have the `setrlimit' function. */
+/*#define HAVE_SETRLIMIT 1*/
+
+/* Define to 1 if you have the setsockopt function. */
+/* #undef HAVE_SETSOCKOPT */
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+/*#define HAVE_SGTTY_H 1*/
+
+/* Define to 1 if you have the `sigaction' function. */
+/*#define HAVE_SIGACTION 1*/
+
+/* Define to 1 if you have the `siginterrupt' function. */
+/*#define HAVE_SIGINTERRUPT 1*/
+
+/* Define to 1 if you have the `signal' function. */
+/*#define HAVE_SIGNAL 1*/
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* If you have sigsetjmp */
+/*#define HAVE_SIGSETJMP 1*/
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+/*#define HAVE_SIG_ATOMIC_T 1*/
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+/*#define HAVE_SSL_GET_SHUTDOWN 1*/
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strcmpi' function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the `stricmp' function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+#define HAVE_STRLCPY 1
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/*#define HAVE_SYS_POLL_H 1*/
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+/*#define HAVE_TERMIOS_H 1*/
+
+/* Define to 1 if you have the <termio.h> header file. */
+/*#define HAVE_TERMIO_H 1*/
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/*#define HAVE_TLD_H 1*/
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/*#define HAVE_TLD_STRERROR 1*/
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+/*#define HAVE_VARIADIC_MACROS_GCC 1*/
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+/*#define HAVE_WRITABLE_ARGV 1*/
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* cpu-machine-OS */
+#ifdef __WINS__
+#define OS "i386-pc-epoc32"
+#elif __MARM__
+#define OS "arm-unknown-epoc32"
+#else
+/* This won't happen on any current Symbian version */
+#define OS "unknown-unknown-epoc32"
+#endif
+
+/* Name of package */
+/*#define PACKAGE "curl"*/
+
+/* Define to the address where bug reports for this package should be sent. */
+/*#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"*/
+
+/* Define to the full name of this package. */
+/*#define PACKAGE_NAME "curl"*/
+
+/* Define to the full name and version of this package. */
+/*#define PACKAGE_STRING "curl -"*/
+
+/* Define to the one symbol short name of this package. */
+/*#define PACKAGE_TARNAME "curl"*/
+
+/* Define to the version of this package. */
+/*#define PACKAGE_VERSION "-"*/
+
+/* a suitable file to read random data from */
+/*#define RANDOM_FILE "/dev/urandom"*/
+
+#define RECV_TYPE_ARG1 int
+#define RECV_TYPE_ARG2 void*
+#define RECV_TYPE_ARG3 size_t
+#define RECV_TYPE_ARG4 int
+#define RECV_TYPE_RETV ssize_t
+
+#define RECVFROM_TYPE_ARG1 int
+#define RECVFROM_TYPE_ARG2 void
+#define RECVFROM_TYPE_ARG3 size_t
+#define RECVFROM_TYPE_ARG4 int
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+#define RECVFROM_TYPE_ARG6 size_t
+#define RECVFROM_TYPE_RETV ssize_t
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+#define SEND_TYPE_ARG1 int
+#define SEND_QUAL_ARG2 const
+#define SEND_TYPE_ARG2 void*
+#define SEND_TYPE_ARG3 size_t
+#define SEND_TYPE_ARG4 int
+#define SEND_TYPE_RETV ssize_t
+
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+/*#define RETSIGTYPE void*/
+
+/* Define to the type of arg 1 for `select'. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#define SELECT_TYPE_ARG234 (fd_set *)
+
+/* Define to the type of arg 5 for `select'. */
+#define SELECT_TYPE_ARG5 (struct timeval *)
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/*#define USE_LIBSSH2 1*/
+
+/* If you want to build curl with the built-in manual */
+/*#define USE_MANUAL 1*/
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Version number of package */
+/*#define VERSION "7.18.2-CVS"*/
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* # undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+#define _FILE_OFFSET_BITS 64
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* type to use in place of in_addr_t if not defined */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* Enabling curl debug mode when building in Symbian debug mode would work */
+/* except that debug mode introduces new exports that must be frozen. */
+#ifdef _DEBUG
+/* #define CURLDEBUG */
+#endif
+
+/* sys/cdefs.h fails to define this for WINSCW prior to Symbian OS ver. 9.4 */
+#ifndef __LONG_LONG_SUPPORTED
+#define __LONG_LONG_SUPPORTED
+#endif
+
+/* Enable appropriate header only when zlib support is enabled */
+#ifdef HAVE_LIBZ
+#define HAVE_ZLIB_H 1
+#endif
+
+/* Enable appropriate definitions only when OpenSSL support is enabled */
+#ifdef USE_SSLEAY
+/* if OpenSSL is in use */
+#define USE_OPENSSL
+#endif
+
+#endif /* HEADER_CURL_CONFIG_SYMBIAN_H */
diff --git a/libs/libcurl/src/config-tpf.h b/libs/libcurl/src/config-tpf.h
new file mode 100644
index 0000000000..ddb8f778c2
--- /dev/null
+++ b/libs/libcurl/src/config-tpf.h
@@ -0,0 +1,773 @@
+#ifndef HEADER_CURL_CONFIG_TPF_H
+#define HEADER_CURL_CONFIG_TPF_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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for TPF */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/* FEATURES, FUNCTIONS, and DEFINITIONS */
+/* ---------------------------------------------------------------- */
+
+/* NOTE: Refer also to the .mak file for some of the flags below */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+/* #undef CURL_DISABLE_FTP */
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+/* #undef CURL_DISABLE_LDAP */
+
+/* to disable TELNET */
+/* #undef CURL_DISABLE_TELNET */
+
+/* to disable TFTP */
+/* #undef CURL_DISABLE_TFTP */
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* lber dynamic library file */
+/* #undef DL_LBER_FILE */
+
+/* ldap dynamic library file */
+/* #undef DL_LDAP_FILE */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+/* #undef ENABLE_IPV6 */
+
+/* Define if struct sockaddr_in6 has the sin6_scope_id member */
+/* #undef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID */
+
+/* Define to the type of arg 1 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG1 */
+
+/* Define to the type of arg 2 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG2 */
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG46 */
+
+/* Define to the type of arg 7 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG7 */
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+/* #undef HAVE_ARPA_TFTP_H */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+#define HAVE_BASENAME 1
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+/* #undef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+#define HAVE_CRYPTO_H 1
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+#define HAVE_DES_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+/* #undef HAVE_ENGINE_LOAD_BUILTIN_ENGINES */
+#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+#define HAVE_ERR_H 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the `fork' function. */
+/* #undef HAVE_FORK */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the `ftruncate' function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if getaddrinfo exists and works */
+/* #undef HAVE_GETADDRINFO */
+
+/* Define to 1 if you have the `geteuid' function. */
+#define HAVE_GETEUID 1
+
+/* Define to 1 if you have the `gethostbyaddr' function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* If you have gethostbyname */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the `gethostbyname_r' function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 1 */
+
+/* Define to 1 if you have the getnameinfo function. */
+/* #undef HAVE_GETNAMEINFO */
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getprotobyname' function. */
+/* #undef HAVE_GETPROTOBYNAME */
+
+/* Define to 1 if you have the `getpwuid' function. */
+#define HAVE_GETPWUID 1
+
+/* Define to 1 if you have the `getrlimit' function. */
+/* #undef HAVE_GETRLIMIT */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+#define HAVE_GETTIMEOFDAY 1
+
+/* we have a glibc-style strerror_r() */
+/* #undef HAVE_GLIBC_STRERROR_R */
+#define HAVE_GLIBC_STRERROR_R 1
+
+/* Define to 1 if you have the `gmtime_r' function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `iconv' functions. */
+#define HAVE_ICONV 1
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+/* #undef HAVE_INET_NTOP */
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+/* #undef HAVE_INET_PTON */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have the <io.h> header file. */
+/* #undef HAVE_IO_H */
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+/* #undef HAVE_LIBGEN_H 1 */
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+/* #undef HAVE_LIBSSL */
+#define HAVE_LIBSSL 1
+
+/* if zlib is available */
+/* #undef HAVE_LIBZ */
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have the `localtime_r' function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you have the <memory.h> header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+/* undef HAVE_NETINET_TCP_H */
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define if NI_WITHSCOPEID exists and works */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* we have no strerror_r() proto */
+/* #undef HAVE_NO_STRERROR_R_DECL */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+/* #undef HAVE_OPENSSL_CRYPTO_H */
+#define HAVE_OPENSSL_CRYPTO_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+/* #undef HAVE_OPENSSL_ENGINE_H */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+/* #undef HAVE_OPENSSL_ERR_H */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+/* #undef HAVE_OPENSSL_PEM_H */
+#define HAVE_OPENSSL_PEM_H 1
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+/* #undef HAVE_OPENSSL_PKCS12_H */
+#define HAVE_OPENSSL_PKCS12_H 1
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+/* #undef HAVE_OPENSSL_RSA_H */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+/* #undef HAVE_OPENSSL_SSL_H */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+/* #undef HAVE_OPENSSL_X509_H */
+#define HAVE_OPENSSL_X509_H 1
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+#define HAVE_PEM_H 1
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* Define to 1 if you have the `poll' function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* we have a POSIX-style strerror_r() */
+/* #undef HAVE_POSIX_STRERROR_R */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+#define HAVE_PWD_H 1
+
+/* Define to 1 if you have the `RAND_egd' function. */
+/* #undef HAVE_RAND_EGD */
+#define HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+/* #undef HAVE_RAND_STATUS */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+#define HAVE_RSA_H 1
+
+/* Define to 1 if you have the `select' function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+/* #undef HAVE_SETSOCKOPT */
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+/* #undef HAVE_SGTTY_H 1 */
+
+/* Define to 1 if you have the `sigaction' function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the `siginterrupt' function. */
+/* #undef HAVE_SIGINTERRUPT */
+
+/* Define to 1 if you have the `signal' function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* If you have sigsetjmp */
+/* #undef HAVE_SIGSETJMP */
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+#define HAVE_SSL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#define HAVE_STDINT_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the `strcasecmp' function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the `strcmpi' function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the `strdup' function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the `strerror_r' function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the `stricmp' function. */
+/* #undef HAVE_STRICMP */
+#define HAVE_STRICMP 1
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the `strstr' function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the `strtok_r' function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the `strtoll' function. */
+#define HAVE_STRTOLL 1
+
+/* if struct sockaddr_storage is defined */
+/* #undef HAVE_STRUCT_SOCKADDR_STORAGE */
+
+/* Define this if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+#define HAVE_SYS_FILIO_H 1
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+#define HAVE_SYS_PARAM_H 1
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/* #undef HAVE_SYS_POLL_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+#define HAVE_SYS_SELECT_H 1
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+#define HAVE_SYS_SOCKIO_H 1
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+#define HAVE_SYS_TIME_H 1
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+/* #undef HAVE_SYS_UTIME_H */
+
+/* Define to 1 if you have the <termios.h> header file. */
+/* #undef HAVE_TERMIOS_H */
+
+/* Define to 1 if you have the <termio.h> header file. */
+/* #undef HAVE_TERMIO_H */
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if you have the <winsock2.h> header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the <winsock.h> header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+/* #undef HAVE_WRITABLE_ARGV */
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+/* #undef HAVE_ZLIB_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* cpu-machine-OS */
+#define OS "s390x-ibm-tpf"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* Define to the address where bug reports for this package should be sent. */
+#define PACKAGE_BUGREPORT "a suitable curl mailing list => http://curl.haxx.se/mail/"
+
+/* Define to the full name of this package. */
+#define PACKAGE_NAME "curl"
+
+/* Define to the full name and version of this package. */
+#define PACKAGE_STRING "curl -"
+
+/* Define to the one symbol short name of this package. */
+#define PACKAGE_TARNAME "curl"
+
+/* Define to the version of this package. */
+#define PACKAGE_VERSION "-"
+
+/* a suitable file to read random data from */
+/* #undef RANDOM_FILE */
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type of arg 1 for `select'. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for `select'. */
+#define SELECT_TYPE_ARG234 (fd_set *)
+
+/* Define to the type of arg 5 for `select'. */
+#define SELECT_TYPE_ARG5 (struct timeval *)
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 8
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 8
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+#define TIME_WITH_SYS_TIME 1
+
+/* Define if you want to enable ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* If you want to build curl with the built-in manual */
+/* #undef USE_MANUAL */
+
+/* if OpenSSL is in use */
+/* #undef USE_OPENSSL */
+
+/* if SSL is enabled */
+/* #undef USE_SSLEAY */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Version number of package */
+#define VERSION "not-used"
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if on AIX 3.
+ System headers sometimes define this.
+ We just want to avoid a redefinition error message. */
+#ifndef _ALL_SOURCE
+/* # undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* type to use in place of in_addr_t if not defined */
+/* #undef in_addr_t */
+
+/* Define to `unsigned' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+/* Define to 1 if you have the getnameinfo function. */
+/* #undef HAVE_GETNAMEINFO 1 */
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+/* #undef GETNAMEINFO_QUAL_ARG1 const */
+
+/* Define to the type of arg 1 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG1 struct sockaddr * */
+
+/* Define to the type of arg 2 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG2 socklen_t */
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG46 size_t */
+
+/* Define to the type of arg 7 for getnameinfo. */
+/* #undef GETNAMEINFO_TYPE_ARG7 int */
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+#define CURL_DOES_CONVERSIONS
+#ifndef CURL_ICONV_CODESET_OF_HOST
+#define CURL_ICONV_CODESET_OF_HOST "IBM-1047"
+#endif
+
+
+#endif /* HEADER_CURL_CONFIG_TPF_H */
diff --git a/libs/libcurl/src/config-vxworks.h b/libs/libcurl/src/config-vxworks.h
new file mode 100644
index 0000000000..c94534afb8
--- /dev/null
+++ b/libs/libcurl/src/config-vxworks.h
@@ -0,0 +1,934 @@
+#ifndef HEADER_CURL_CONFIG_VXWORKS_H
+#define HEADER_CURL_CONFIG_VXWORKS_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.
+ *
+ ***************************************************************************/
+
+/* =============================================================== */
+/* Hand crafted config file for VxWorks */
+/* =============================================================== */
+
+/* Location of default ca bundle */
+/* #undef CURL_CA_BUNDLE */
+
+/* Location of default ca path */
+/* #undef CURL_CA_PATH */
+
+/* to disable cookies support */
+/* #undef CURL_DISABLE_COOKIES */
+
+/* to disable cryptographic authentication */
+/* #undef CURL_DISABLE_CRYPTO_AUTH */
+
+/* to disable DICT */
+/* #undef CURL_DISABLE_DICT */
+
+/* to disable FILE */
+/* #undef CURL_DISABLE_FILE */
+
+/* to disable FTP */
+#define CURL_DISABLE_FTP 1
+
+/* to disable HTTP */
+/* #undef CURL_DISABLE_HTTP */
+
+/* to disable LDAP */
+#define CURL_DISABLE_LDAP 1
+
+/* to disable LDAPS */
+#define CURL_DISABLE_LDAPS 1
+
+/* to disable NTLM authentication */
+#define CURL_DISABLE_NTLM 1
+
+/* to disable proxies */
+/* #undef CURL_DISABLE_PROXY */
+
+/* to disable TELNET */
+#define CURL_DISABLE_TELNET 1
+
+/* to disable TFTP */
+#define CURL_DISABLE_TFTP 1
+
+/* to disable verbose strings */
+/* #undef CURL_DISABLE_VERBOSE_STRINGS */
+
+/* Definition to make a library symbol externally visible. */
+/* #undef CURL_EXTERN_SYMBOL */
+
+/* Use Windows LDAP implementation */
+/* #undef CURL_LDAP_WIN */
+
+/* your Entropy Gathering Daemon socket pathname */
+/* #undef EGD_SOCKET */
+
+/* Define if you want to enable IPv6 support */
+#define ENABLE_IPV6 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 size_t
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 unsigned int
+
+/* Specifies the number of arguments to getservbyport_r */
+#define GETSERVBYPORT_R_ARGS 6
+
+/* Specifies the size of the buffer to pass to getservbyport_r */
+#define GETSERVBYPORT_R_BUFSIZE 4096
+
+/* Define to 1 if you have the alarm function. */
+#define HAVE_ALARM 1
+
+/* Define to 1 if you have the <alloca.h> header file. */
+#define HAVE_ALLOCA_H 1
+
+/* Define to 1 if you have the <arpa/inet.h> header file. */
+#define HAVE_ARPA_INET_H 1
+
+/* Define to 1 if you have the <arpa/tftp.h> header file. */
+/* #undef HAVE_ARPA_TFTP_H */
+
+/* Define to 1 if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define to 1 if you have the `basename' function. */
+/* #undef HAVE_BASENAME */
+
+/* Define to 1 if bool is an available type. */
+#define HAVE_BOOL_T 1
+
+/* Define to 1 if you have the clock_gettime function and monotonic timer. */
+/* #undef HAVE_CLOCK_GETTIME_MONOTONIC */
+
+/* Define to 1 if you have the `closesocket' function. */
+/* #undef HAVE_CLOSESOCKET */
+
+/* Define to 1 if you have the `CRYPTO_cleanup_all_ex_data' function. */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define to 1 if you have the <crypto.h> header file. */
+/* #undef HAVE_CRYPTO_H */
+
+/* Define to 1 if you have the <des.h> header file. */
+/* #undef HAVE_DES_H */
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#define HAVE_DLFCN_H 1
+
+/* Define to 1 if you have the `ENGINE_load_builtin_engines' function. */
+#define HAVE_ENGINE_LOAD_BUILTIN_ENGINES 1
+
+/* Define to 1 if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define to 1 if you have the <err.h> header file. */
+/* #undef HAVE_ERR_H */
+
+/* Define to 1 if you have the fcntl function. */
+#define HAVE_FCNTL 1
+
+/* Define to 1 if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define to 1 if you have a working fcntl O_NONBLOCK function. */
+#define HAVE_FCNTL_O_NONBLOCK 1
+
+/* Define to 1 if you have the fdopen function. */
+#define HAVE_FDOPEN 1
+
+/* Define to 1 if you have the `fork' function. */
+#define HAVE_FORK 1
+
+/* Define to 1 if you have the freeaddrinfo function. */
+#define HAVE_FREEADDRINFO 1
+
+/* Define to 1 if you have the freeifaddrs function. */
+#define HAVE_FREEIFADDRS 1
+
+/* Define to 1 if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define to 1 if you have a working getaddrinfo function. */
+#define HAVE_GETADDRINFO 1
+
+/* Define to 1 if you have the `geteuid' function. */
+/* #undef HAVE_GETEUID */
+
+/* Define to 1 if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define to 1 if you have the gethostbyaddr_r function. */
+#define HAVE_GETHOSTBYADDR_R 1
+
+/* gethostbyaddr_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYADDR_R_5 */
+
+/* gethostbyaddr_r() takes 7 args */
+/* #undef HAVE_GETHOSTBYADDR_R_7 */
+
+/* gethostbyaddr_r() takes 8 args */
+#define HAVE_GETHOSTBYADDR_R_8 1
+
+/* Define to 1 if you have the gethostbyname function. */
+#define HAVE_GETHOSTBYNAME 1
+
+/* Define to 1 if you have the gethostbyname_r function. */
+/* #undef HAVE_GETHOSTBYNAME_R */
+
+/* gethostbyname_r() takes 3 args */
+/* #undef HAVE_GETHOSTBYNAME_R_3 */
+
+/* gethostbyname_r() takes 5 args */
+/* #undef HAVE_GETHOSTBYNAME_R_5 */
+
+/* gethostbyname_r() takes 6 args */
+/* #undef HAVE_GETHOSTBYNAME_R_6 */
+
+/* Define to 1 if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define to 1 if you have a working getifaddrs function. */
+/* #undef HAVE_GETIFADDRS */
+
+/* Define to 1 if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to 1 if you have the `getpass_r' function. */
+/* #undef HAVE_GETPASS_R */
+
+/* Define to 1 if you have the `getppid' function. */
+#define HAVE_GETPPID 1
+
+/* Define to 1 if you have the `getprotobyname' function. */
+#define HAVE_GETPROTOBYNAME 1
+
+/* Define to 1 if you have the `getpwuid' function. */
+/* #undef HAVE_GETPWUID */
+
+/* Define to 1 if you have the `getrlimit' function. */
+#define HAVE_GETRLIMIT 1
+
+/* Define to 1 if you have the getservbyport_r function. */
+/* #undef HAVE_GETSERVBYPORT_R */
+
+/* Define to 1 if you have the `gettimeofday' function. */
+/* #undef HAVE_GETTIMEOFDAY */
+
+/* Define to 1 if you have a working glibc-style strerror_r function. */
+/* #undef HAVE_GLIBC_STRERROR_R */
+
+/* Define to 1 if you have a working gmtime_r function. */
+#define HAVE_GMTIME_R 1
+
+/* if you have the gssapi libraries */
+/* #undef HAVE_GSSAPI */
+
+/* Define to 1 if you have the <gssapi/gssapi_generic.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_GENERIC_H */
+
+/* Define to 1 if you have the <gssapi/gssapi.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_H */
+
+/* Define to 1 if you have the <gssapi/gssapi_krb5.h> header file. */
+/* #undef HAVE_GSSAPI_GSSAPI_KRB5_H */
+
+/* if you have the GNU gssapi libraries */
+/* #undef HAVE_GSSGNU */
+
+/* if you have the Heimdal gssapi libraries */
+/* #undef HAVE_GSSHEIMDAL */
+
+/* if you have the MIT gssapi libraries */
+/* #undef HAVE_GSSMIT */
+
+/* Define to 1 if you have the `idna_strerror' function. */
+/* #undef HAVE_IDNA_STRERROR */
+
+/* Define to 1 if you have the `idn_free' function. */
+/* #undef HAVE_IDN_FREE */
+
+/* Define to 1 if you have the <idn-free.h> header file. */
+/* #undef HAVE_IDN_FREE_H */
+
+/* Define to 1 if you have the <ifaddrs.h> header file. */
+/* #undef HAVE_IFADDRS_H */
+
+/* Define to 1 if you have the `inet_addr' function. */
+#define HAVE_INET_ADDR 1
+
+/* Define to 1 if you have the inet_ntoa_r function. */
+/* #undef HAVE_INET_NTOA_R */
+
+/* inet_ntoa_r() takes 2 args */
+/* #undef HAVE_INET_NTOA_R_2 */
+
+/* inet_ntoa_r() takes 3 args */
+/* #undef HAVE_INET_NTOA_R_3 */
+
+/* Define to 1 if you have a IPv6 capable working inet_ntop function. */
+/* #undef HAVE_INET_NTOP */
+
+/* Define to 1 if you have a IPv6 capable working inet_pton function. */
+/* #undef HAVE_INET_PTON */
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#define HAVE_INTTYPES_H 1
+
+/* Define to 1 if you have the ioctl function. */
+#define HAVE_IOCTL 1
+
+/* Define to 1 if you have the ioctlsocket function. */
+/* #undef HAVE_IOCTLSOCKET */
+
+/* Define to 1 if you have the IoctlSocket camel case function. */
+/* #undef HAVE_IOCTLSOCKET_CAMEL */
+
+/* Define to 1 if you have a working IoctlSocket camel case FIONBIO function.
+ */
+/* #undef HAVE_IOCTLSOCKET_CAMEL_FIONBIO */
+
+/* Define to 1 if you have a working ioctlsocket FIONBIO function. */
+/* #undef HAVE_IOCTLSOCKET_FIONBIO */
+
+/* Define to 1 if you have a working ioctl FIONBIO function. */
+#define HAVE_IOCTL_FIONBIO 1
+
+/* Define to 1 if you have a working ioctl SIOCGIFADDR function. */
+#define HAVE_IOCTL_SIOCGIFADDR 1
+
+/* Define to 1 if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* if you have the Kerberos4 libraries (including -ldes) */
+/* #undef HAVE_KRB4 */
+
+/* Define to 1 if you have the `krb_get_our_ip_for_realm' function. */
+/* #undef HAVE_KRB_GET_OUR_IP_FOR_REALM */
+
+/* Define to 1 if you have the <krb.h> header file. */
+/* #undef HAVE_KRB_H */
+
+/* Define to 1 if you have the lber.h header file. */
+/* #undef HAVE_LBER_H */
+
+/* Define to 1 if you have the ldapssl.h header file. */
+/* #undef HAVE_LDAPSSL_H */
+
+/* Define to 1 if you have the ldap.h header file. */
+/* #undef HAVE_LDAP_H */
+
+/* Use LDAPS implementation */
+/* #undef HAVE_LDAP_SSL */
+
+/* Define to 1 if you have the ldap_ssl.h header file. */
+/* #undef HAVE_LDAP_SSL_H */
+
+/* Define to 1 if you have the `ldap_url_parse' function. */
+/* #undef HAVE_LDAP_URL_PARSE */
+
+/* Define to 1 if you have the <libgen.h> header file. */
+/* #undef HAVE_LIBGEN_H */
+
+/* Define to 1 if you have the `idn' library (-lidn). */
+/* #undef HAVE_LIBIDN */
+
+/* Define to 1 if you have the `resolv' library (-lresolv). */
+/* #undef HAVE_LIBRESOLV */
+
+/* Define to 1 if you have the `resolve' library (-lresolve). */
+/* #undef HAVE_LIBRESOLVE */
+
+/* Define to 1 if you have the `socket' library (-lsocket). */
+/* #undef HAVE_LIBSOCKET */
+
+/* Define to 1 if you have the `ssh2' library (-lssh2). */
+/* #undef HAVE_LIBSSH2 */
+
+/* Define to 1 if you have the <libssh2.h> header file. */
+/* #undef HAVE_LIBSSH2_H */
+
+/* Define to 1 if you have the `libssh2_version' function. */
+/* #undef HAVE_LIBSSH2_VERSION */
+
+/* Define to 1 if you have the `ssl' library (-lssl). */
+#define HAVE_LIBSSL 1
+
+/* if zlib is available */
+#define HAVE_LIBZ 1
+
+/* Define to 1 if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* if your compiler supports LL */
+#define HAVE_LL 1
+
+/* Define to 1 if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define to 1 if you have a working localtime_r function. */
+#define HAVE_LOCALTIME_R 1
+
+/* Define to 1 if the compiler supports the 'long long' data type. */
+#define HAVE_LONGLONG 1
+
+/* Define to 1 if you have the malloc.h header file. */
+#define HAVE_MALLOC_H 1
+
+/* Define to 1 if you have the memory.h header file. */
+#define HAVE_MEMORY_H 1
+
+/* Define to 1 if you have the MSG_NOSIGNAL flag. */
+/* #undef HAVE_MSG_NOSIGNAL */
+
+/* Define to 1 if you have the <netdb.h> header file. */
+#define HAVE_NETDB_H 1
+
+/* Define to 1 if you have the <netinet/in.h> header file. */
+#define HAVE_NETINET_IN_H 1
+
+/* Define to 1 if you have the <netinet/tcp.h> header file. */
+#define HAVE_NETINET_TCP_H 1
+
+/* Define to 1 if you have the <net/if.h> header file. */
+#define HAVE_NET_IF_H 1
+
+/* Define to 1 if NI_WITHSCOPEID exists and works. */
+/* #undef HAVE_NI_WITHSCOPEID */
+
+/* if you have an old MIT gssapi library, lacking GSS_C_NT_HOSTBASED_SERVICE
+ */
+/* #undef HAVE_OLD_GSSMIT */
+
+/* Define to 1 if you have the <openssl/crypto.h> header file. */
+#define HAVE_OPENSSL_CRYPTO_H 1
+
+/* Define to 1 if you have the <openssl/engine.h> header file. */
+#define HAVE_OPENSSL_ENGINE_H 1
+
+/* Define to 1 if you have the <openssl/err.h> header file. */
+#define HAVE_OPENSSL_ERR_H 1
+
+/* Define to 1 if you have the <openssl/pem.h> header file. */
+#define HAVE_OPENSSL_PEM_H 1
+
+/* Define to 1 if you have the <openssl/pkcs12.h> header file. */
+#define HAVE_OPENSSL_PKCS12_H 1
+
+/* Define to 1 if you have the <openssl/rsa.h> header file. */
+#define HAVE_OPENSSL_RSA_H 1
+
+/* Define to 1 if you have the <openssl/ssl.h> header file. */
+#define HAVE_OPENSSL_SSL_H 1
+
+/* Define to 1 if you have the <openssl/x509.h> header file. */
+#define HAVE_OPENSSL_X509_H 1
+
+/* Define to 1 if you have the <pem.h> header file. */
+/* #undef HAVE_PEM_H */
+
+/* Define to 1 if you have the `perror' function. */
+#define HAVE_PERROR 1
+
+/* Define to 1 if you have the `pipe' function. */
+#define HAVE_PIPE 1
+
+/* Define to 1 if you have a working poll function. */
+/* #undef HAVE_POLL */
+
+/* If you have a fine poll */
+/* #undef HAVE_POLL_FINE */
+
+/* Define to 1 if you have the <poll.h> header file. */
+/* #undef HAVE_POLL_H */
+
+/* Define to 1 if you have a working POSIX-style strerror_r function. */
+/* #undef HAVE_POSIX_STRERROR_R */
+
+/* Define to 1 if you have the <pwd.h> header file. */
+/* #undef HAVE_PWD_H */
+
+/* Define to 1 if you have the `RAND_egd' function. */
+#define HAVE_RAND_EGD 1
+
+/* Define to 1 if you have the `RAND_screen' function. */
+/* #undef HAVE_RAND_SCREEN */
+
+/* Define to 1 if you have the `RAND_status' function. */
+#define HAVE_RAND_STATUS 1
+
+/* Define to 1 if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to 1 if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to 1 if you have the <rsa.h> header file. */
+/* #undef HAVE_RSA_H */
+
+/* Define to 1 if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define to 1 if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to 1 if you have the <setjmp.h> header file. */
+#define HAVE_SETJMP_H 1
+
+/* Define to 1 if you have the `setlocale' function. */
+#define HAVE_SETLOCALE 1
+
+/* Define to 1 if you have the `setmode' function. */
+#define HAVE_SETMODE 1
+
+/* Define to 1 if you have the `setrlimit' function. */
+#define HAVE_SETRLIMIT 1
+
+/* Define to 1 if you have the setsockopt function. */
+#define HAVE_SETSOCKOPT 1
+
+/* Define to 1 if you have a working setsockopt SO_NONBLOCK function. */
+/* #undef HAVE_SETSOCKOPT_SO_NONBLOCK */
+
+/* Define to 1 if you have the <sgtty.h> header file. */
+/* #undef HAVE_SGTTY_H */
+
+/* Define to 1 if you have the sigaction function. */
+#define HAVE_SIGACTION 1
+
+/* Define to 1 if you have the siginterrupt function. */
+#define HAVE_SIGINTERRUPT 1
+
+/* Define to 1 if you have the signal function. */
+#define HAVE_SIGNAL 1
+
+/* Define to 1 if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define to 1 if you have the sigsetjmp function or macro. */
+/* #undef HAVE_SIGSETJMP */
+
+/* Define to 1 if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define to 1 if sig_atomic_t is already defined as volatile. */
+/* #undef HAVE_SIG_ATOMIC_T_VOLATILE */
+
+/* Define to 1 if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* Define to 1 if you have the `socket' function. */
+#define HAVE_SOCKET 1
+
+/* Define this if you have the SPNEGO library fbopenssl */
+/* #undef HAVE_SPNEGO */
+
+/* Define to 1 if you have the `SSL_get_shutdown' function. */
+#define HAVE_SSL_GET_SHUTDOWN 1
+
+/* Define to 1 if you have the <ssl.h> header file. */
+/* #undef HAVE_SSL_H */
+
+/* Define to 1 if you have the <stdbool.h> header file. */
+#define HAVE_STDBOOL_H 1
+
+/* Define to 1 if you have the <stdint.h> header file. */
+/* #undef HAVE_STDINT_H */
+
+/* Define to 1 if you have the <stdio.h> header file. */
+#define HAVE_STDIO_H 1
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define to 1 if you have the strcasecmp function. */
+#define HAVE_STRCASECMP 1
+
+/* Define to 1 if you have the strcmpi function. */
+/* #undef HAVE_STRCMPI */
+
+/* Define to 1 if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define to 1 if you have the strerror_r function. */
+#define HAVE_STRERROR_R 1
+
+/* Define to 1 if you have the stricmp function. */
+/* #undef HAVE_STRICMP */
+
+/* Define to 1 if you have the <strings.h> header file. */
+#define HAVE_STRINGS_H 1
+
+/* Define to 1 if you have the <string.h> header file. */
+#define HAVE_STRING_H 1
+
+/* Define to 1 if you have the `strlcpy' function. */
+/* #undef HAVE_STRLCPY */
+
+/* Define to 1 if you have the strncasecmp function. */
+#define HAVE_STRNCASECMP 1
+
+/* Define to 1 if you have the strncmpi function. */
+/* #undef HAVE_STRNCMPI */
+
+/* Define to 1 if you have the strnicmp function. */
+/* #undef HAVE_STRNICMP */
+
+/* Define to 1 if you have the <stropts.h> header file. */
+/* #undef HAVE_STROPTS_H */
+
+/* Define to 1 if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define to 1 if you have the strtok_r function. */
+#define HAVE_STRTOK_R 1
+
+/* Define to 1 if you have the strtoll function. */
+/* #undef HAVE_STRTOLL */
+
+/* if struct sockaddr_storage is defined */
+#define HAVE_STRUCT_SOCKADDR_STORAGE 1
+
+/* Define to 1 if you have the timeval struct. */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define to 1 if you have the <sys/filio.h> header file. */
+/* #undef HAVE_SYS_FILIO_H */
+
+/* Define to 1 if you have the <sys/ioctl.h> header file. */
+#define HAVE_SYS_IOCTL_H 1
+
+/* Define to 1 if you have the <sys/param.h> header file. */
+/* #undef HAVE_SYS_PARAM_H */
+
+/* Define to 1 if you have the <sys/poll.h> header file. */
+/* #undef HAVE_SYS_POLL_H */
+
+/* Define to 1 if you have the <sys/resource.h> header file. */
+#define HAVE_SYS_RESOURCE_H 1
+
+/* Define to 1 if you have the <sys/select.h> header file. */
+/* #undef HAVE_SYS_SELECT_H */
+
+/* Define to 1 if you have the <sys/socket.h> header file. */
+#define HAVE_SYS_SOCKET_H 1
+
+/* Define to 1 if you have the <sys/sockio.h> header file. */
+/* #undef HAVE_SYS_SOCKIO_H */
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define to 1 if you have the <sys/time.h> header file. */
+/* #undef HAVE_SYS_TIME_H */
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define to 1 if you have the <sys/uio.h> header file. */
+#define HAVE_SYS_UIO_H 1
+
+/* Define to 1 if you have the <sys/un.h> header file. */
+#define HAVE_SYS_UN_H 1
+
+/* Define to 1 if you have the <sys/utime.h> header file. */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define to 1 if you have the <termios.h> header file. */
+#define HAVE_TERMIOS_H 1
+
+/* Define to 1 if you have the <termio.h> header file. */
+#define HAVE_TERMIO_H 1
+
+/* Define to 1 if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define to 1 if you have the <tld.h> header file. */
+/* #undef HAVE_TLD_H */
+
+/* Define to 1 if you have the `tld_strerror' function. */
+/* #undef HAVE_TLD_STRERROR */
+
+/* Define to 1 if you have the `uname' function. */
+#define HAVE_UNAME 1
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#define HAVE_UNISTD_H 1
+
+/* Define to 1 if you have the `utime' function. */
+#define HAVE_UTIME 1
+
+/* Define to 1 if you have the <utime.h> header file. */
+#define HAVE_UTIME_H 1
+
+/* Define to 1 if compiler supports C99 variadic macro style. */
+#define HAVE_VARIADIC_MACROS_C99 1
+
+/* Define to 1 if compiler supports old gcc variadic macro style. */
+#define HAVE_VARIADIC_MACROS_GCC 1
+
+/* Define to 1 if you have a working vxworks-style strerror_r function. */
+#define HAVE_VXWORKS_STRERROR_R 1
+
+/* Define to 1 if you have the winber.h header file. */
+/* #undef HAVE_WINBER_H */
+
+/* Define to 1 if you have the windows.h header file. */
+/* #undef HAVE_WINDOWS_H */
+
+/* Define to 1 if you have the winldap.h header file. */
+/* #undef HAVE_WINLDAP_H */
+
+/* Define to 1 if you have the winsock2.h header file. */
+/* #undef HAVE_WINSOCK2_H */
+
+/* Define to 1 if you have the winsock.h header file. */
+/* #undef HAVE_WINSOCK_H */
+
+/* Define this symbol if your OS supports changing the contents of argv */
+#define HAVE_WRITABLE_ARGV 1
+
+/* Define to 1 if you have the writev function. */
+#define HAVE_WRITEV 1
+
+/* Define to 1 if you have the ws2tcpip.h header file. */
+/* #undef HAVE_WS2TCPIP_H */
+
+/* Define to 1 if you have the <x509.h> header file. */
+/* #undef HAVE_X509_H */
+
+/* if you have the zlib.h header file */
+#define HAVE_ZLIB_H 1
+
+/* Define to 1 if you need the lber.h header file even with ldap.h */
+/* #undef NEED_LBER_H */
+
+/* Define to 1 if you need the malloc.h header file even with stdlib.h */
+/* #undef NEED_MALLOC_H */
+
+/* Define to 1 if you need the memory.h header file even with stdlib.h */
+/* #undef NEED_MEMORY_H */
+
+/* Define to 1 if _REENTRANT preprocessor symbol must be defined. */
+/* #undef NEED_REENTRANT */
+
+/* Define to 1 if _THREAD_SAFE preprocessor symbol must be defined. */
+/* #undef NEED_THREAD_SAFE */
+
+/* Define to 1 if the open function requires three arguments. */
+#define OPEN_NEEDS_ARG3 1
+
+/* cpu-machine-OS */
+#define OS "unknown-unknown-vxworks"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* a suitable file to read random data from */
+#define RANDOM_FILE "/dev/urandom"
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 int
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 void
+
+/* Define to 1 if the type pointed by arg 2 for recvfrom is void. */
+#define RECVFROM_TYPE_ARG2_IS_VOID 1
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to 1 if the type pointed by arg 5 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG5_IS_VOID */
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 socklen_t
+
+/* Define to 1 if the type pointed by arg 6 for recvfrom is void. */
+/* #undef RECVFROM_TYPE_ARG6_IS_VOID */
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define as the return type of signal handlers (`int' or `void'). */
+#define RETSIGTYPE void
+
+/* Define to the type qualifier of arg 5 for select. */
+#define SELECT_QUAL_ARG5
+
+/* Define to the type of arg 1 for select. */
+#define SELECT_TYPE_ARG1 int
+
+/* Define to the type of args 2, 3 and 4 for select. */
+#define SELECT_TYPE_ARG234 fd_set *
+
+/* Define to the type of arg 5 for select. */
+#define SELECT_TYPE_ARG5 struct timeval *
+
+/* Define to the function return type for select. */
+#define SELECT_TYPE_RETV int
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 int
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 void *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 size_t
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long', as computed by sizeof. */
+#define SIZEOF_LONG 4
+
+/* The size of `off_t', as computed by sizeof. */
+#define SIZEOF_OFF_T 8
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#define SIZEOF_SIZE_T 4
+
+/* The size of `time_t', as computed by sizeof. */
+#define SIZEOF_TIME_T 4
+
+/* The size of `void*', as computed by sizeof. */
+#define SIZEOF_VOIDP 4
+
+/* Define to 1 if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define to the type of arg 3 for strerror_r. */
+/* #undef STRERROR_R_TYPE_ARG3 */
+
+/* Define to 1 if you can safely include both <sys/time.h> and <time.h>. */
+/* #undef TIME_WITH_SYS_TIME */
+
+/* Define if you want to enable c-ares support */
+/* #undef USE_ARES */
+
+/* Define to disable non-blocking sockets. */
+/* #undef USE_BLOCKING_SOCKETS */
+
+/* if GnuTLS is enabled */
+/* #undef USE_GNUTLS */
+
+/* if libSSH2 is in use */
+/* #undef USE_LIBSSH2 */
+
+/* If you want to build curl with the built-in manual */
+#define USE_MANUAL 1
+
+/* if NSS is enabled */
+/* #undef USE_NSS */
+
+/* if OpenSSL is in use */
+#define USE_OPENSSL 1
+
+/* if SSL is enabled */
+#define USE_SSLEAY 1
+
+/* Define to 1 if you are building a Windows target without large file
+ support. */
+/* #undef USE_WIN32_LARGE_FILES */
+
+/* to enable SSPI support */
+/* #undef USE_WINDOWS_SSPI */
+
+/* Define to 1 if using yaSSL in OpenSSL compatibility mode. */
+/* #undef USE_YASSLEMUL */
+
+/* Define to avoid automatic inclusion of winsock.h */
+/* #undef WIN32_LEAN_AND_MEAN */
+
+/* Define to 1 if OS is AIX. */
+#ifndef _ALL_SOURCE
+/* # undef _ALL_SOURCE */
+#endif
+
+/* Number of bits in a file offset, on hosts where this is settable. */
+/* #undef _FILE_OFFSET_BITS */
+
+/* Define for large files, on AIX-style hosts. */
+/* #undef _LARGE_FILES */
+
+/* Define to empty if `const' does not conform to ANSI C. */
+/* #undef const */
+
+/* Type to use in place of in_addr_t when system does not provide it. */
+/* #undef in_addr_t */
+
+/* Define to `__inline__' or `__inline' if that's what the C compiler
+ calls it, or to nothing if 'inline' is not supported under any name. */
+#ifndef __cplusplus
+/* #undef inline */
+#endif
+
+/* Define to `unsigned int' if <sys/types.h> does not define. */
+/* #undef size_t */
+
+/* the signed version of size_t */
+/* #undef ssize_t */
+
+#endif /* HEADER_CURL_CONFIG_VXWORKS_H */
diff --git a/libs/libcurl/src/config-win32.h b/libs/libcurl/src/config-win32.h
new file mode 100644
index 0000000000..59ba4e538f
--- /dev/null
+++ b/libs/libcurl/src/config-win32.h
@@ -0,0 +1,681 @@
+#ifndef HEADER_CURL_CONFIG_WIN32_H
+#define HEADER_CURL_CONFIG_WIN32_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* Hand crafted config file for Windows */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/* HEADER FILES */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the <arpa/inet.h> header file. */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <assert.h> header file. */
+#define HAVE_ASSERT_H 1
+
+/* Define if you have the <crypto.h> header file. */
+/* #define HAVE_CRYPTO_H 1 */
+
+/* Define if you have the <errno.h> header file. */
+#define HAVE_ERRNO_H 1
+
+/* Define if you have the <err.h> header file. */
+/* #define HAVE_ERR_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+#if defined(__MINGW32__) || defined(__POCC__)
+#define HAVE_GETOPT_H 1
+#endif
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you have the <locale.h> header file. */
+#define HAVE_LOCALE_H 1
+
+/* Define if you need <malloc.h> header even with <stdlib.h> header file. */
+#if !defined(__SALFORDC__) && !defined(__POCC__)
+#define NEED_MALLOC_H 1
+#endif
+
+/* Define if you have the <netdb.h> header file. */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file. */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <process.h> header file. */
+#ifndef __SALFORDC__
+#define HAVE_PROCESS_H 1
+#endif
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define if you have the <sgtty.h> header file. */
+/* #define HAVE_SGTTY_H 1 */
+
+/* Define if you have the <ssl.h> header file. */
+/* #define HAVE_SSL_H 1 */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <sys/param.h> header file. */
+/* #define HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/select.h> header file. */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file. */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file. */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <sys/types.h> header file. */
+#define HAVE_SYS_TYPES_H 1
+
+/* Define if you have the <sys/utime.h> header file. */
+#ifndef __BORLANDC__
+#define HAVE_SYS_UTIME_H 1
+#endif
+
+/* Define if you have the <termio.h> header file. */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file. */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__) || \
+ defined(__POCC__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if you have the <windows.h> header file. */
+#define HAVE_WINDOWS_H 1
+
+/* Define if you have the <winsock.h> header file. */
+#define HAVE_WINSOCK_H 1
+
+/* Define if you have the <winsock2.h> header file. */
+#ifndef __SALFORDC__
+#define HAVE_WINSOCK2_H 1
+#endif
+
+/* Define if you have the <ws2tcpip.h> header file. */
+#ifndef __SALFORDC__
+#define HAVE_WS2TCPIP_H 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/* OTHER HEADER INFO */
+/* ---------------------------------------------------------------- */
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* ---------------------------------------------------------------- */
+/* FUNCTIONS */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function. */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #define HAVE_DOPRNT 1 */
+
+/* Define if you have the ftruncate function. */
+#define HAVE_FTRUNCATE 1
+
+/* Define if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getpass function. */
+/* #define HAVE_GETPASS 1 */
+
+/* Define if you have the getservbyname function. */
+#define HAVE_GETSERVBYNAME 1
+
+/* Define if you have the getprotobyname function. */
+#define HAVE_GETPROTOBYNAME
+
+/* Define if you have the gettimeofday function. */
+/* #define HAVE_GETTIMEOFDAY 1 */
+
+/* Define if you have the inet_addr function. */
+#define HAVE_INET_ADDR 1
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the perror function. */
+#define HAVE_PERROR 1
+
+/* Define if you have the RAND_screen function when using SSL. */
+#define HAVE_RAND_SCREEN 1
+
+/* Define if you have the `RAND_status' function when using SSL. */
+#define HAVE_RAND_STATUS 1
+
+/* Define if you have the `CRYPTO_cleanup_all_ex_data' function.
+ This is present in OpenSSL versions after 0.9.6b */
+#define HAVE_CRYPTO_CLEANUP_ALL_EX_DATA 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setlocale function. */
+#define HAVE_SETLOCALE 1
+
+/* Define if you have the setmode function. */
+#define HAVE_SETMODE 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function. */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define if you have the strdup function. */
+#define HAVE_STRDUP 1
+
+/* Define if you have the strftime function. */
+#define HAVE_STRFTIME 1
+
+/* Define if you have the stricmp function. */
+#define HAVE_STRICMP 1
+
+/* Define if you have the strncasecmp function. */
+/* #define HAVE_STRNCASECMP 1 */
+
+/* Define if you have the strnicmp function. */
+#define HAVE_STRNICMP 1
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtoll function. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__POCC__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the tcgetattr function. */
+/* #define HAVE_TCGETATTR 1 */
+
+/* Define if you have the tcsetattr function. */
+/* #define HAVE_TCSETATTR 1 */
+
+/* Define if you have the utime function. */
+#ifndef __BORLANDC__
+#define HAVE_UTIME 1
+#endif
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 DWORD
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 SOCKET
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* ---------------------------------------------------------------- */
+/* TYPEDEF REPLACEMENTS */
+/* ---------------------------------------------------------------- */
+
+/* Define if in_addr_t is not an available 'typedefed' type. */
+#define in_addr_t unsigned long
+
+/* Define to the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define if ssize_t is not an available 'typedefed' type. */
+#ifndef _SSIZE_T_DEFINED
+# if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || \
+ defined(__POCC__) || \
+ defined(__MINGW32__)
+# elif defined(_WIN64)
+# define _SSIZE_T_DEFINED
+# define ssize_t __int64
+# else
+# define _SSIZE_T_DEFINED
+# define ssize_t int
+# endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/* TYPE SIZES */
+/* ---------------------------------------------------------------- */
+
+/* Define to the size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* Define to the size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* Define to the size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* Define to the size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* Define to the size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+# define SIZEOF_SIZE_T 8
+#else
+# define SIZEOF_SIZE_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/* BSD-style lwIP TCP/IP stack SPECIFIC */
+/* ---------------------------------------------------------------- */
+
+/* Define to use BSD-style lwIP TCP/IP stack. */
+/* #define USE_LWIPSOCK 1 */
+
+#ifdef USE_LWIPSOCK
+# undef USE_WINSOCK
+# undef HAVE_WINSOCK_H
+# undef HAVE_WINSOCK2_H
+# undef HAVE_WS2TCPIP_H
+# undef HAVE_ERRNO_H
+# undef HAVE_GETHOSTNAME
+# undef HAVE_GETNAMEINFO
+# undef LWIP_POSIX_SOCKETS_IO_NAMES
+# undef RECV_TYPE_ARG1
+# undef RECV_TYPE_ARG3
+# undef SEND_TYPE_ARG1
+# undef SEND_TYPE_ARG3
+# define HAVE_FREEADDRINFO
+# define HAVE_GETADDRINFO
+# define HAVE_GETHOSTBYNAME
+# define HAVE_GETHOSTBYNAME_R
+# define HAVE_GETHOSTBYNAME_R_6
+# define LWIP_POSIX_SOCKETS_IO_NAMES 0
+# define RECV_TYPE_ARG1 int
+# define RECV_TYPE_ARG3 size_t
+# define SEND_TYPE_ARG1 int
+# define SEND_TYPE_ARG3 size_t
+#endif
+
+/* ---------------------------------------------------------------- */
+/* Watt-32 tcp/ip SPECIFIC */
+/* ---------------------------------------------------------------- */
+
+#ifdef USE_WATT32
+ #include <tcp.h>
+ #undef byte
+ #undef word
+ #undef USE_WINSOCK
+ #undef HAVE_WINSOCK_H
+ #undef HAVE_WINSOCK2_H
+ #undef HAVE_WS2TCPIP_H
+ #define HAVE_GETADDRINFO
+ #define HAVE_GETNAMEINFO
+ #define HAVE_SYS_IOCTL_H
+ #define HAVE_SYS_SOCKET_H
+ #define HAVE_NETINET_IN_H
+ #define HAVE_NETDB_H
+ #define HAVE_ARPA_INET_H
+ #define HAVE_FREEADDRINFO
+ #define SOCKET int
+#endif
+
+
+/* ---------------------------------------------------------------- */
+/* COMPILER SPECIFIC */
+/* ---------------------------------------------------------------- */
+
+/* Define to nothing if compiler does not support 'const' qualifier. */
+/* #define const */
+
+/* Define to nothing if compiler does not support 'volatile' qualifier. */
+/* #define volatile */
+
+/* Windows should not have HAVE_GMTIME_R defined */
+/* #undef HAVE_GMTIME_R */
+
+/* Define if the compiler supports C99 variadic macro style. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define HAVE_VARIADIC_MACROS_C99 1
+#endif
+
+/* Define if the compiler supports the 'long long' data type. */
+#if defined(__MINGW32__) || defined(__WATCOMC__)
+#define HAVE_LONGLONG 1
+#endif
+
+/* Define to avoid VS2005 complaining about portable C functions. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* VS2005 and later dafault size for time_t is 64-bit, unless
+ _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# ifndef _USE_32BIT_TIME_T
+# define SIZEOF_TIME_T 8
+# else
+# define SIZEOF_TIME_T 4
+# endif
+#endif
+
+/* Officially, Microsoft's Windows SDK versions 6.X do not support Windows
+ 2000 as a supported build target. VS2008 default installations provide
+ an embedded Windows SDK v6.0A along with the claim that Windows 2000 is
+ a valid build target for VS2008. Popular belief is that binaries built
+ with VS2008 using Windows SDK versions 6.X and Windows 2000 as a build
+ target are functional. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+# define VS2008_MIN_TARGET 0x0500
+#endif
+
+/* When no build target is specified VS2008 default build target is Windows
+ Vista, which leaves out even Winsows XP. If no build target has been given
+ for VS2008 we will target the minimum Officially supported build target,
+ which happens to be Windows XP. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+# define VS2008_DEF_TARGET 0x0501
+#endif
+
+/* VS2008 default target settings and minimum build target check. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1500)
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT VS2008_DEF_TARGET
+# endif
+# ifndef WINVER
+# define WINVER VS2008_DEF_TARGET
+# endif
+# if (_WIN32_WINNT < VS2008_MIN_TARGET) || (WINVER < VS2008_MIN_TARGET)
+# error VS2008 does not support Windows build targets prior to Windows 2000
+# endif
+#endif
+
+/* When no build target is specified Pelles C 5.00 and later default build
+ target is Windows Vista. We override default target to be Windows 2000. */
+#if defined(__POCC__) && (__POCC__ >= 500)
+# ifndef _WIN32_WINNT
+# define _WIN32_WINNT 0x0500
+# endif
+# ifndef WINVER
+# define WINVER 0x0500
+# endif
+#endif
+
+/* Availability of freeaddrinfo, getaddrinfo and getnameinfo functions is
+ quite convoluted, compiler dependent and even build target dependent. */
+#if defined(HAVE_WS2TCPIP_H)
+# if defined(__POCC__)
+# define HAVE_FREEADDRINFO 1
+# define HAVE_GETADDRINFO 1
+# define HAVE_GETADDRINFO_THREADSAFE 1
+# define HAVE_GETNAMEINFO 1
+# elif defined(_WIN32_WINNT) && (_WIN32_WINNT >= 0x0501)
+# define HAVE_FREEADDRINFO 1
+# define HAVE_GETADDRINFO 1
+# define HAVE_GETADDRINFO_THREADSAFE 1
+# define HAVE_GETNAMEINFO 1
+# elif defined(_MSC_VER) && (_MSC_VER >= 1200)
+# define HAVE_FREEADDRINFO 1
+# define HAVE_GETADDRINFO 1
+# define HAVE_GETADDRINFO_THREADSAFE 1
+# define HAVE_GETNAMEINFO 1
+# endif
+#endif
+
+#if defined(__POCC__)
+# ifndef _MSC_VER
+# error Microsoft extensions /Ze compiler option is required
+# endif
+# ifndef __POCC__OLDNAMES
+# error Compatibility names /Go compiler option is required
+# 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 */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define USE_WIN32_LARGE_FILES
+# else
+# define USE_WIN32_SMALL_FILES
+# endif
+#endif
+
+#if defined(__MINGW32__) && !defined(USE_WIN32_LARGE_FILES)
+# define USE_WIN32_LARGE_FILES
+#endif
+
+#if defined(__WATCOMC__) && !defined(USE_WIN32_LARGE_FILES)
+# define USE_WIN32_LARGE_FILES
+#endif
+
+#if defined(__POCC__)
+# undef USE_WIN32_LARGE_FILES
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+# define USE_WIN32_SMALL_FILES
+#endif
+
+/* ---------------------------------------------------------------- */
+/* DNS RESOLVER SPECIALTY */
+/* ---------------------------------------------------------------- */
+
+/*
+ * Undefine both USE_ARES and USE_THREADS_WIN32 for synchronous DNS.
+ */
+
+/* Define to enable c-ares asynchronous DNS lookups. */
+/* #define USE_ARES 1 */
+
+/* Default define to enable threaded asynchronous DNS lookups. */
+#if !defined(USE_SYNC_DNS) && !defined(USE_ARES) && \
+ !defined(USE_THREADS_WIN32)
+# define USE_THREADS_WIN32 1
+#endif
+
+#if defined(USE_ARES) && defined(USE_THREADS_WIN32)
+# error "Only one DNS lookup specialty may be defined at most"
+#endif
+
+/* ---------------------------------------------------------------- */
+/* LDAP SUPPORT */
+/* ---------------------------------------------------------------- */
+
+#if defined(CURL_HAS_NOVELL_LDAPSDK) || defined(CURL_HAS_MOZILLA_LDAPSDK)
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_SSL_H 1
+#define HAVE_LDAP_URL_PARSE 1
+#elif defined(CURL_HAS_OPENLDAP_LDAPSDK)
+#undef CURL_LDAP_WIN
+#define HAVE_LDAP_URL_PARSE 1
+#else
+#undef HAVE_LDAP_URL_PARSE
+#define CURL_LDAP_WIN 1
+#endif
+
+#if defined(__WATCOMC__) && defined(CURL_LDAP_WIN)
+#if __WATCOMC__ < 1280
+#define WINBERAPI __declspec(cdecl)
+#define WINLDAPAPI __declspec(cdecl)
+#endif
+#endif
+
+#if defined(__POCC__) && defined(CURL_LDAP_WIN)
+# define CURL_DISABLE_LDAP 1
+#endif
+
+/* ---------------------------------------------------------------- */
+/* ADDITIONAL DEFINITIONS */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#undef OS
+#if defined(_M_IX86) || defined(__i386__) /* x86 (MSVC or gcc) */
+#define OS "i386-pc-win32"
+#elif defined(_M_X64) || defined(__x86_64__) /* x86_64 (MSVC >=2005 or gcc) */
+#define OS "x86_64-pc-win32"
+#elif defined(_M_IA64) /* Itanium */
+#define OS "ia64-pc-win32"
+#else
+#define OS "unknown-pc-win32"
+#endif
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* If you want to build curl with the built-in manual */
+#define USE_MANUAL 1
+
+#if defined(__POCC__) || (USE_IPV6)
+# define ENABLE_IPV6 1
+#endif
+
+#endif /* HEADER_CURL_CONFIG_WIN32_H */
diff --git a/libs/libcurl/src/config-win32ce.h b/libs/libcurl/src/config-win32ce.h
new file mode 100644
index 0000000000..a8ab0d34e2
--- /dev/null
+++ b/libs/libcurl/src/config-win32ce.h
@@ -0,0 +1,448 @@
+#ifndef HEADER_CURL_CONFIG_WIN32CE_H
+#define HEADER_CURL_CONFIG_WIN32CE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/* ================================================================ */
+/* lib/config-win32ce.h - Hand crafted config file for windows ce */
+/* ================================================================ */
+
+/* ---------------------------------------------------------------- */
+/* HEADER FILES */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the <arpa/inet.h> header file. */
+/* #define HAVE_ARPA_INET_H 1 */
+
+/* Define if you have the <assert.h> header file. */
+/* #define HAVE_ASSERT_H 1 */
+
+/* Define if you have the <crypto.h> header file. */
+/* #define HAVE_CRYPTO_H 1 */
+
+/* Define if you have the <errno.h> header file. */
+/* #define HAVE_ERRNO_H 1 */
+
+/* Define if you have the <err.h> header file. */
+/* #define HAVE_ERR_H 1 */
+
+/* Define if you have the <fcntl.h> header file. */
+#define HAVE_FCNTL_H 1
+
+/* Define if you have the <getopt.h> header file. */
+/* #define HAVE_GETOPT_H 1 */
+
+/* Define if you have the <io.h> header file. */
+#define HAVE_IO_H 1
+
+/* Define if you have the <limits.h> header file. */
+#define HAVE_LIMITS_H 1
+
+/* Define if you need the malloc.h header header file even with stdlib.h */
+#define NEED_MALLOC_H 1
+
+/* Define if you have the <netdb.h> header file. */
+/* #define HAVE_NETDB_H 1 */
+
+/* Define if you have the <netinet/in.h> header file. */
+/* #define HAVE_NETINET_IN_H 1 */
+
+/* Define if you have the <signal.h> header file. */
+#define HAVE_SIGNAL_H 1
+
+/* Define if you have the <sgtty.h> header file. */
+/* #define HAVE_SGTTY_H 1 */
+
+/* Define if you have the <ssl.h> header file. */
+/* #define HAVE_SSL_H 1 */
+
+/* Define if you have the <stdlib.h> header file. */
+#define HAVE_STDLIB_H 1
+
+/* Define if you have the <process.h> header file. */
+/* #define HAVE_PROCESS_H 1 */
+
+/* Define if you have the <sys/param.h> header file. */
+/* #define HAVE_SYS_PARAM_H 1 */
+
+/* Define if you have the <sys/select.h> header file. */
+/* #define HAVE_SYS_SELECT_H 1 */
+
+/* Define if you have the <sys/socket.h> header file. */
+/* #define HAVE_SYS_SOCKET_H 1 */
+
+/* Define if you have the <sys/sockio.h> header file. */
+/* #define HAVE_SYS_SOCKIO_H 1 */
+
+/* Define if you have the <sys/stat.h> header file. */
+#define HAVE_SYS_STAT_H 1
+
+/* Define if you have the <sys/time.h> header file */
+/* #define HAVE_SYS_TIME_H 1 */
+
+/* Define if you have the <sys/types.h> header file. */
+/* #define HAVE_SYS_TYPES_H 1 */
+
+/* Define if you have the <sys/utime.h> header file */
+#define HAVE_SYS_UTIME_H 1
+
+/* Define if you have the <termio.h> header file. */
+/* #define HAVE_TERMIO_H 1 */
+
+/* Define if you have the <termios.h> header file. */
+/* #define HAVE_TERMIOS_H 1 */
+
+/* Define if you have the <time.h> header file. */
+#define HAVE_TIME_H 1
+
+/* Define if you have the <unistd.h> header file. */
+#if defined(__MINGW32__) || defined(__WATCOMC__) || defined(__LCC__)
+#define HAVE_UNISTD_H 1
+#endif
+
+/* Define if you have the <windows.h> header file. */
+#define HAVE_WINDOWS_H 1
+
+/* Define if you have the <winsock.h> header file. */
+#define HAVE_WINSOCK_H 1
+
+/* Define if you have the <winsock2.h> header file. */
+/* #define HAVE_WINSOCK2_H 1 */
+
+/* Define if you have the <ws2tcpip.h> header file. */
+/* #define HAVE_WS2TCPIP_H 1 */
+
+/* ---------------------------------------------------------------- */
+/* OTHER HEADER INFO */
+/* ---------------------------------------------------------------- */
+
+/* Define if sig_atomic_t is an available typedef. */
+#define HAVE_SIG_ATOMIC_T 1
+
+/* Define if you have the ANSI C header files. */
+#define STDC_HEADERS 1
+
+/* Define if you can safely include both <sys/time.h> and <time.h>. */
+/* #define TIME_WITH_SYS_TIME 1 */
+
+/* ---------------------------------------------------------------- */
+/* FUNCTIONS */
+/* ---------------------------------------------------------------- */
+
+/* Define if you have the closesocket function. */
+#define HAVE_CLOSESOCKET 1
+
+/* Define if you don't have vprintf but do have _doprnt. */
+/* #define HAVE_DOPRNT 1 */
+
+/* Define if you have the gethostbyaddr function. */
+#define HAVE_GETHOSTBYADDR 1
+
+/* Define if you have the gethostname function. */
+#define HAVE_GETHOSTNAME 1
+
+/* Define if you have the getpass function. */
+/* #define HAVE_GETPASS 1 */
+
+/* Define if you have the getservbyname function. */
+#define HAVE_GETSERVBYNAME 1
+
+/* Define if you have the gettimeofday function. */
+/* #define HAVE_GETTIMEOFDAY 1 */
+
+/* Define if you have the inet_addr function. */
+#define HAVE_INET_ADDR 1
+
+/* Define if you have the ioctlsocket function. */
+#define HAVE_IOCTLSOCKET 1
+
+/* Define if you have a working ioctlsocket FIONBIO function. */
+#define HAVE_IOCTLSOCKET_FIONBIO 1
+
+/* Define if you have the perror function. */
+#define HAVE_PERROR 1
+
+/* Define if you have the RAND_screen function when using SSL */
+#define HAVE_RAND_SCREEN 1
+
+/* Define if you have the `RAND_status' function when using SSL. */
+#define HAVE_RAND_STATUS 1
+
+/* Define if you have the select function. */
+#define HAVE_SELECT 1
+
+/* Define if you have the setvbuf function. */
+#define HAVE_SETVBUF 1
+
+/* Define if you have the socket function. */
+#define HAVE_SOCKET 1
+
+/* Define if you have the strcasecmp function. */
+/* #define HAVE_STRCASECMP 1 */
+
+/* Define if you have the strdup function. */
+/* #define HAVE_STRDUP 1 */
+
+/* Define if you have the strftime function. */
+/* #define HAVE_STRFTIME 1 */
+
+/* Define if you have the stricmp function. */
+/* #define HAVE_STRICMP 1 */
+
+/* Define if you have the strncasecmp function. */
+/* #define HAVE_STRNCASECMP 1 */
+
+/* Define if you have the strnicmp function. */
+/* #define HAVE_STRNICMP 1 */
+
+/* Define if you have the strstr function. */
+#define HAVE_STRSTR 1
+
+/* Define if you have the strtoll function. */
+#if defined(__MINGW32__) || defined(__WATCOMC__)
+#define HAVE_STRTOLL 1
+#endif
+
+/* Define if you have the tcgetattr function. */
+/* #define HAVE_TCGETATTR 1 */
+
+/* Define if you have the tcsetattr function. */
+/* #define HAVE_TCSETATTR 1 */
+
+/* Define if you have the utime function */
+#define HAVE_UTIME 1
+
+/* Define if you have the getnameinfo function. */
+#define HAVE_GETNAMEINFO 1
+
+/* Define to the type qualifier of arg 1 for getnameinfo. */
+#define GETNAMEINFO_QUAL_ARG1 const
+
+/* Define to the type of arg 1 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG1 struct sockaddr *
+
+/* Define to the type of arg 2 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG2 socklen_t
+
+/* Define to the type of args 4 and 6 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG46 DWORD
+
+/* Define to the type of arg 7 for getnameinfo. */
+#define GETNAMEINFO_TYPE_ARG7 int
+
+/* Define if you have the recv function. */
+#define HAVE_RECV 1
+
+/* Define to the type of arg 1 for recv. */
+#define RECV_TYPE_ARG1 SOCKET
+
+/* Define to the type of arg 2 for recv. */
+#define RECV_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for recv. */
+#define RECV_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recv. */
+#define RECV_TYPE_ARG4 int
+
+/* Define to the function return type for recv. */
+#define RECV_TYPE_RETV int
+
+/* Define if you have the recvfrom function. */
+#define HAVE_RECVFROM 1
+
+/* Define to the type of arg 1 for recvfrom. */
+#define RECVFROM_TYPE_ARG1 SOCKET
+
+/* Define to the type pointed by arg 2 for recvfrom. */
+#define RECVFROM_TYPE_ARG2 char
+
+/* Define to the type of arg 3 for recvfrom. */
+#define RECVFROM_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for recvfrom. */
+#define RECVFROM_TYPE_ARG4 int
+
+/* Define to the type pointed by arg 5 for recvfrom. */
+#define RECVFROM_TYPE_ARG5 struct sockaddr
+
+/* Define to the type pointed by arg 6 for recvfrom. */
+#define RECVFROM_TYPE_ARG6 int
+
+/* Define to the function return type for recvfrom. */
+#define RECVFROM_TYPE_RETV int
+
+/* Define if you have the send function. */
+#define HAVE_SEND 1
+
+/* Define to the type of arg 1 for send. */
+#define SEND_TYPE_ARG1 SOCKET
+
+/* Define to the type qualifier of arg 2 for send. */
+#define SEND_QUAL_ARG2 const
+
+/* Define to the type of arg 2 for send. */
+#define SEND_TYPE_ARG2 char *
+
+/* Define to the type of arg 3 for send. */
+#define SEND_TYPE_ARG3 int
+
+/* Define to the type of arg 4 for send. */
+#define SEND_TYPE_ARG4 int
+
+/* Define to the function return type for send. */
+#define SEND_TYPE_RETV int
+
+/* ---------------------------------------------------------------- */
+/* TYPEDEF REPLACEMENTS */
+/* ---------------------------------------------------------------- */
+
+/* Define this if in_addr_t is not an available 'typedefed' type */
+#define in_addr_t unsigned long
+
+/* Define as the return type of signal handlers (int or void). */
+#define RETSIGTYPE void
+
+/* Define ssize_t if it is not an available 'typedefed' type */
+#if (defined(__WATCOMC__) && (__WATCOMC__ >= 1240)) || defined(__POCC__)
+#elif defined(_WIN64)
+#define ssize_t __int64
+#else
+#define ssize_t int
+#endif
+
+/* ---------------------------------------------------------------- */
+/* TYPE SIZES */
+/* ---------------------------------------------------------------- */
+
+/* The size of `int', as computed by sizeof. */
+#define SIZEOF_INT 4
+
+/* The size of `long double', as computed by sizeof. */
+#define SIZEOF_LONG_DOUBLE 16
+
+/* The size of `long long', as computed by sizeof. */
+/* #define SIZEOF_LONG_LONG 8 */
+
+/* The size of `short', as computed by sizeof. */
+#define SIZEOF_SHORT 2
+
+/* The size of `size_t', as computed by sizeof. */
+#if defined(_WIN64)
+# define SIZEOF_SIZE_T 8
+#else
+# define SIZEOF_SIZE_T 4
+#endif
+
+/* ---------------------------------------------------------------- */
+/* STRUCT RELATED */
+/* ---------------------------------------------------------------- */
+
+/* Define this if you have struct sockaddr_storage */
+/* #define HAVE_STRUCT_SOCKADDR_STORAGE 1 */
+
+/* Define this if you have struct timeval */
+#define HAVE_STRUCT_TIMEVAL 1
+
+/* Define this if struct sockaddr_in6 has the sin6_scope_id member */
+#define HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID 1
+
+/* ---------------------------------------------------------------- */
+/* COMPILER SPECIFIC */
+/* ---------------------------------------------------------------- */
+
+/* Undef keyword 'const' if it does not work. */
+/* #undef const */
+
+/* Define to avoid VS2005 complaining about portable C functions */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+#define _CRT_SECURE_NO_DEPRECATE 1
+#define _CRT_NONSTDC_NO_DEPRECATE 1
+#endif
+
+/* VS2005 and later dafault size for time_t is 64-bit, unless */
+/* _USE_32BIT_TIME_T has been defined to get a 32-bit time_t. */
+#if defined(_MSC_VER) && (_MSC_VER >= 1400)
+# ifndef _USE_32BIT_TIME_T
+# define SIZEOF_TIME_T 8
+# else
+# define SIZEOF_TIME_T 4
+# endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/* LARGE FILE SUPPORT */
+/* ---------------------------------------------------------------- */
+
+#if defined(_MSC_VER) && !defined(_WIN32_WCE)
+# if (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define USE_WIN32_LARGE_FILES
+# else
+# define USE_WIN32_SMALL_FILES
+# endif
+#endif
+
+#if !defined(USE_WIN32_LARGE_FILES) && !defined(USE_WIN32_SMALL_FILES)
+# define USE_WIN32_SMALL_FILES
+#endif
+
+/* ---------------------------------------------------------------- */
+/* LDAP SUPPORT */
+/* ---------------------------------------------------------------- */
+
+#define CURL_LDAP_WIN 1
+#undef HAVE_LDAP_URL_PARSE
+
+/* ---------------------------------------------------------------- */
+/* ADDITIONAL DEFINITIONS */
+/* ---------------------------------------------------------------- */
+
+/* Define cpu-machine-OS */
+#undef OS
+#define OS "i386-pc-win32ce"
+
+/* Name of package */
+#define PACKAGE "curl"
+
+/* ---------------------------------------------------------------- */
+/* WinCE */
+/* ---------------------------------------------------------------- */
+
+#ifndef UNICODE
+# define UNICODE
+#endif
+
+#ifndef _UNICODE
+# define _UNICODE
+#endif
+
+#define CURL_DISABLE_FILE 1
+#define CURL_DISABLE_TELNET 1
+#define CURL_DISABLE_LDAP 1
+
+#define ENOSPC 1
+#define ENOMEM 2
+#define EAGAIN 3
+
+extern int stat(const char *path,struct stat *buffer );
+
+#endif /* HEADER_CURL_CONFIG_WIN32CE_H */
diff --git a/libs/libcurl/src/conncache.c b/libs/libcurl/src/conncache.c
new file mode 100644
index 0000000000..48271f7510
--- /dev/null
+++ b/libs/libcurl/src/conncache.c
@@ -0,0 +1,280 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Linus Nielsen Feltzing, <linus@haxx.se>
+ * Copyright (C) 2012 - 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 <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "bundles.h"
+#include "conncache.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void free_bundle_hash_entry(void *freethis)
+{
+ struct connectbundle *b = (struct connectbundle *) freethis;
+
+ Curl_bundle_destroy(b);
+}
+
+struct conncache *Curl_conncache_init(int size)
+{
+ struct conncache *connc;
+
+ connc = calloc(1, sizeof(struct conncache));
+ if(!connc)
+ return NULL;
+
+ connc->hash = Curl_hash_alloc(size, Curl_hash_str,
+ Curl_str_key_compare, free_bundle_hash_entry);
+
+ if(!connc->hash) {
+ free(connc);
+ return NULL;
+ }
+
+ return connc;
+}
+
+void Curl_conncache_destroy(struct conncache *connc)
+{
+ if(connc) {
+ Curl_hash_destroy(connc->hash);
+ connc->hash = NULL;
+ free(connc);
+ }
+}
+
+struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
+ char *hostname)
+{
+ struct connectbundle *bundle = NULL;
+
+ if(connc)
+ bundle = Curl_hash_pick(connc->hash, hostname, strlen(hostname)+1);
+
+ return bundle;
+}
+
+static bool conncache_add_bundle(struct conncache *connc,
+ char *hostname,
+ struct connectbundle *bundle)
+{
+ void *p;
+
+ p = Curl_hash_add(connc->hash, hostname, strlen(hostname)+1, bundle);
+
+ return p?TRUE:FALSE;
+}
+
+static void conncache_remove_bundle(struct conncache *connc,
+ struct connectbundle *bundle)
+{
+ struct curl_hash_iterator iter;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ Curl_hash_start_iterate(connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ if(he->ptr == bundle) {
+ /* The bundle is destroyed by the hash destructor function,
+ free_bundle_hash_entry() */
+ Curl_hash_delete(connc->hash, he->key, he->key_len);
+ return;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+}
+
+CURLcode Curl_conncache_add_conn(struct conncache *connc,
+ struct connectdata *conn)
+{
+ CURLcode result;
+ struct connectbundle *bundle;
+ struct connectbundle *new_bundle = NULL;
+ struct SessionHandle *data = conn->data;
+
+ bundle = Curl_conncache_find_bundle(data->state.conn_cache,
+ conn->host.name);
+ if(!bundle) {
+ result = Curl_bundle_create(data, &new_bundle);
+ if(result != CURLE_OK)
+ return result;
+
+ if(!conncache_add_bundle(data->state.conn_cache,
+ conn->host.name, new_bundle)) {
+ Curl_bundle_destroy(new_bundle);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ bundle = new_bundle;
+ }
+
+ result = Curl_bundle_add_conn(bundle, conn);
+ if(result != CURLE_OK) {
+ if(new_bundle)
+ conncache_remove_bundle(data->state.conn_cache, new_bundle);
+ return result;
+ }
+
+ connc->num_connections++;
+
+ return CURLE_OK;
+}
+
+void Curl_conncache_remove_conn(struct conncache *connc,
+ struct connectdata *conn)
+{
+ struct connectbundle *bundle = conn->bundle;
+
+ /* The bundle pointer can be NULL, since this function can be called
+ due to a failed connection attempt, before being added to a bundle */
+ if(bundle) {
+ Curl_bundle_remove_conn(bundle, conn);
+ if(bundle->num_connections == 0) {
+ conncache_remove_bundle(connc, bundle);
+ }
+ connc->num_connections--;
+
+ DEBUGF(infof(conn->data, "The cache now contains %d members\n",
+ connc->num_connections));
+ }
+}
+
+/* This function iterates the entire connection cache and calls the
+ function func() with the connection pointer as the first argument
+ and the supplied 'param' argument as the other,
+
+ Return 0 from func() to continue the loop, return 1 to abort it.
+ */
+void Curl_conncache_foreach(struct conncache *connc,
+ void *param,
+ int (*func)(struct connectdata *conn, void *param))
+{
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ Curl_hash_start_iterate(connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectbundle *bundle;
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ curr = bundle->conn_list->head;
+ while(curr) {
+ /* Yes, we need to update curr before calling func(), because func()
+ might decide to remove the connection */
+ conn = curr->ptr;
+ curr = curr->next;
+
+ if(1 == func(conn, param))
+ return;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+}
+
+/* Return the first connection found in the cache. Used when closing all
+ connections */
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc)
+{
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+ struct connectbundle *bundle;
+
+ Curl_hash_start_iterate(connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ bundle = he->ptr;
+
+ curr = bundle->conn_list->head;
+ if(curr) {
+ return curr->ptr;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+
+ return NULL;
+}
+
+
+#if 0
+/* Useful for debugging the connection cache */
+void Curl_conncache_print(struct conncache *connc)
+{
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+
+ if(!connc)
+ return;
+
+ fprintf(stderr, "=Bundle cache=\n");
+
+ Curl_hash_start_iterate(connc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectbundle *bundle;
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ fprintf(stderr, "%s -", he->key);
+ curr = bundle->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+
+ fprintf(stderr, " [%p %d]", (void *)conn, conn->inuse);
+ curr = curr->next;
+ }
+ fprintf(stderr, "\n");
+
+ he = Curl_hash_next_element(&iter);
+ }
+}
+#endif
diff --git a/libs/libcurl/src/conncache.h b/libs/libcurl/src/conncache.h
new file mode 100644
index 0000000000..f5e41f187b
--- /dev/null
+++ b/libs/libcurl/src/conncache.h
@@ -0,0 +1,53 @@
+#ifndef HEADER_CURL_CONNCACHE_H
+#define HEADER_CURL_CONNCACHE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, 2013, Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+struct conncache {
+ struct curl_hash *hash;
+ size_t num_connections;
+};
+
+struct conncache *Curl_conncache_init(int size);
+
+void Curl_conncache_destroy(struct conncache *connc);
+
+struct connectbundle *Curl_conncache_find_bundle(struct conncache *connc,
+ char *hostname);
+
+CURLcode Curl_conncache_add_conn(struct conncache *connc,
+ struct connectdata *conn);
+
+void Curl_conncache_remove_conn(struct conncache *connc,
+ struct connectdata *conn);
+
+void Curl_conncache_foreach(struct conncache *connc,
+ void *param,
+ int (*func)(struct connectdata *conn,
+ void *param));
+
+struct connectdata *
+Curl_conncache_find_first_connection(struct conncache *connc);
+
+void Curl_conncache_print(struct conncache *connc);
+
+#endif /* HEADER_CURL_CONNCACHE_H */
diff --git a/libs/libcurl/src/connect.c b/libs/libcurl/src/connect.c
new file mode 100644
index 0000000000..2b5719d123
--- /dev/null
+++ b/libs/libcurl/src/connect.c
@@ -0,0 +1,1331 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h> /* <netinet/tcp.h> may need it */
+#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h> /* for sockaddr_un */
+#endif
+#ifdef HAVE_NETINET_TCP_H
+#include <netinet/tcp.h> /* for TCP_NODELAY */
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "strerror.h"
+#include "connect.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "url.h" /* for Curl_safefree() */
+#include "multiif.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "sslgen.h" /* for Curl_ssl_check_cxn() */
+#include "progress.h"
+#include "warnless.h"
+#include "conncache.h"
+#include "multihandle.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef __SYMBIAN32__
+/* This isn't actually supported under Symbian OS */
+#undef SO_NOSIGPIPE
+#endif
+
+static bool verifyconnect(curl_socket_t sockfd, int *error);
+
+#if defined(__DragonFly__) || defined(HAVE_WINSOCK_H)
+/* DragonFlyBSD and Windows use millisecond units */
+#define KEEPALIVE_FACTOR(x) (x *= 1000)
+#else
+#define KEEPALIVE_FACTOR(x)
+#endif
+
+#if defined(HAVE_WINSOCK_H) && !defined(SIO_KEEPALIVE_VALS)
+#define SIO_KEEPALIVE_VALS _WSAIOW(IOC_VENDOR,4)
+
+struct tcp_keepalive {
+ u_long onoff;
+ u_long keepalivetime;
+ u_long keepaliveinterval;
+};
+#endif
+
+static void
+tcpkeepalive(struct SessionHandle *data,
+ curl_socket_t sockfd)
+{
+ int optval = data->set.tcp_keepalive?1:0;
+
+ /* only set IDLE and INTVL if setting KEEPALIVE is successful */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set SO_KEEPALIVE on fd %d\n", sockfd);
+ }
+ else {
+#if defined(SIO_KEEPALIVE_VALS)
+ struct tcp_keepalive vals;
+ DWORD dummy;
+ vals.onoff = 1;
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ vals.keepalivetime = optval;
+ optval = curlx_sltosi(data->set.tcp_keepintvl);
+ KEEPALIVE_FACTOR(optval);
+ vals.keepaliveinterval = optval;
+ if(WSAIoctl(sockfd, SIO_KEEPALIVE_VALS, (LPVOID) &vals, sizeof(vals),
+ NULL, 0, &dummy, NULL, NULL) != 0) {
+ infof(data, "Failed to set SIO_KEEPALIVE_VALS on fd %d: %d\n",
+ (int)sockfd, WSAGetLastError());
+ }
+#else
+#ifdef TCP_KEEPIDLE
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPIDLE on fd %d\n", sockfd);
+ }
+#endif
+#ifdef TCP_KEEPINTVL
+ optval = curlx_sltosi(data->set.tcp_keepintvl);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPINTVL on fd %d\n", sockfd);
+ }
+#endif
+#ifdef TCP_KEEPALIVE
+ /* Mac OS X style */
+ optval = curlx_sltosi(data->set.tcp_keepidle);
+ KEEPALIVE_FACTOR(optval);
+ if(setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPALIVE,
+ (void *)&optval, sizeof(optval)) < 0) {
+ infof(data, "Failed to set TCP_KEEPALIVE on fd %d\n", sockfd);
+ }
+#endif
+#endif
+ }
+}
+
+static CURLcode
+singleipconnect(struct connectdata *conn,
+ const Curl_addrinfo *ai, /* start connecting to this */
+ curl_socket_t *sock,
+ bool *connected);
+
+/*
+ * Curl_timeleft() returns the amount of milliseconds left allowed for the
+ * transfer/connection. If the value is negative, the timeout time has already
+ * elapsed.
+ *
+ * The start time is stored in progress.t_startsingle - as set with
+ * Curl_pgrsTime(..., TIMER_STARTSINGLE);
+ *
+ * If 'nowp' is non-NULL, it points to the current time.
+ * 'duringconnect' is FALSE if not during a connect, as then of course the
+ * connect timeout is not taken into account!
+ *
+ * @unittest: 1303
+ */
+long Curl_timeleft(struct SessionHandle *data,
+ struct timeval *nowp,
+ bool duringconnect)
+{
+ int timeout_set = 0;
+ long timeout_ms = duringconnect?DEFAULT_CONNECT_TIMEOUT:0;
+ struct timeval now;
+
+ /* if a timeout is set, use the most restrictive one */
+
+ if(data->set.timeout > 0)
+ timeout_set |= 1;
+ if(duringconnect && (data->set.connecttimeout > 0))
+ timeout_set |= 2;
+
+ switch (timeout_set) {
+ case 1:
+ timeout_ms = data->set.timeout;
+ break;
+ case 2:
+ timeout_ms = data->set.connecttimeout;
+ break;
+ case 3:
+ if(data->set.timeout < data->set.connecttimeout)
+ timeout_ms = data->set.timeout;
+ else
+ timeout_ms = data->set.connecttimeout;
+ break;
+ default:
+ /* use the default */
+ if(!duringconnect)
+ /* if we're not during connect, there's no default timeout so if we're
+ at zero we better just return zero and not make it a negative number
+ by the math below */
+ return 0;
+ break;
+ }
+
+ if(!nowp) {
+ now = Curl_tvnow();
+ nowp = &now;
+ }
+
+ /* subtract elapsed time */
+ timeout_ms -= Curl_tvdiff(*nowp, data->progress.t_startsingle);
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+
+ return timeout_ms;
+}
+
+/*
+ * checkconnect() checks for a TCP connect on the given socket.
+ * It returns:
+ */
+
+enum chkconn_t {
+ CHKCONN_SELECT_ERROR = -1,
+ CHKCONN_CONNECTED = 0,
+ CHKCONN_IDLE = 1,
+ CHKCONN_FDSET_ERROR = 2
+};
+
+static enum chkconn_t
+checkconnect(curl_socket_t sockfd)
+{
+ int rc;
+#ifdef mpeix
+ /* Call this function once now, and ignore the results. We do this to
+ "clear" the error state on the socket so that we can later read it
+ reliably. This is reported necessary on the MPE/iX operating system. */
+ (void)verifyconnect(sockfd, NULL);
+#endif
+
+ rc = Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 0);
+
+ if(-1 == rc)
+ /* error, no connect here, try next */
+ return CHKCONN_SELECT_ERROR;
+
+ else if(rc & CURL_CSELECT_ERR)
+ /* error condition caught */
+ return CHKCONN_FDSET_ERROR;
+
+ else if(rc)
+ return CHKCONN_CONNECTED;
+
+ return CHKCONN_IDLE;
+}
+
+static CURLcode bindlocal(struct connectdata *conn,
+ curl_socket_t sockfd, int af)
+{
+ struct SessionHandle *data = conn->data;
+
+ struct Curl_sockaddr_storage sa;
+ struct sockaddr *sock = (struct sockaddr *)&sa; /* bind to this address */
+ curl_socklen_t sizeof_sa = 0; /* size of the data sock points to */
+ struct sockaddr_in *si4 = (struct sockaddr_in *)&sa;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *si6 = (struct sockaddr_in6 *)&sa;
+#endif
+
+ struct Curl_dns_entry *h=NULL;
+ unsigned short port = data->set.localport; /* use this port number, 0 for
+ "random" */
+ /* how many port numbers to try to bind to, increasing one at a time */
+ int portnum = data->set.localportrange;
+ const char *dev = data->set.str[STRING_DEVICE];
+ int error;
+ char myhost[256] = "";
+ int done = 0; /* -1 for error, 1 for address found */
+ bool is_interface = FALSE;
+ bool is_host = FALSE;
+ static const char *if_prefix = "if!";
+ static const char *host_prefix = "host!";
+
+ /*************************************************************
+ * Select device to bind socket to
+ *************************************************************/
+ if(!dev && !port)
+ /* no local kind of binding was requested */
+ return CURLE_OK;
+
+ memset(&sa, 0, sizeof(struct Curl_sockaddr_storage));
+
+ if(dev && (strlen(dev)<255) ) {
+ if(strncmp(if_prefix, dev, strlen(if_prefix)) == 0) {
+ dev += strlen(if_prefix);
+ is_interface = TRUE;
+ }
+ else if(strncmp(host_prefix, dev, strlen(host_prefix)) == 0) {
+ dev += strlen(host_prefix);
+ is_host = TRUE;
+ }
+
+ /* interface */
+ if(!is_host) {
+ switch(Curl_if2ip(af, conn->scope, dev, myhost, sizeof(myhost))) {
+ case IF2IP_NOT_FOUND:
+ if(is_interface) {
+ /* Do not fall back to treating it as a host name */
+ failf(data, "Couldn't bind to interface '%s'", dev);
+ return CURLE_INTERFACE_FAILED;
+ }
+ break;
+ case IF2IP_AF_NOT_SUPPORTED:
+ /* Signal the caller to try another address family if available */
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ case IF2IP_FOUND:
+ is_interface = TRUE;
+ /*
+ * We now have the numerical IP address in the 'myhost' buffer
+ */
+ infof(data, "Local Interface %s is ip %s using address family %i\n",
+ dev, myhost, af);
+ done = 1;
+
+#ifdef SO_BINDTODEVICE
+ /* I am not sure any other OSs than Linux that provide this feature,
+ * and at the least I cannot test. --Ben
+ *
+ * This feature allows one to tightly bind the local socket to a
+ * particular interface. This will force even requests to other
+ * local interfaces to go out the external interface.
+ *
+ *
+ * Only bind to the interface when specified as interface, not just
+ * as a hostname or ip address.
+ */
+ if(setsockopt(sockfd, SOL_SOCKET, SO_BINDTODEVICE,
+ dev, (curl_socklen_t)strlen(dev)+1) != 0) {
+ error = SOCKERRNO;
+ infof(data, "SO_BINDTODEVICE %s failed with errno %d: %s;"
+ " will do regular bind\n",
+ dev, error, Curl_strerror(conn, error));
+ /* This is typically "errno 1, error: Operation not permitted" if
+ you're not running as root or another suitable privileged
+ user */
+ }
+#endif
+ break;
+ }
+ }
+ if(!is_interface) {
+ /*
+ * This was not an interface, resolve the name as a host name
+ * or IP number
+ *
+ * Temporarily force name resolution to use only the address type
+ * of the connection. The resolve functions should really be changed
+ * to take a type parameter instead.
+ */
+ long ipver = conn->ip_version;
+ int rc;
+
+ if(af == AF_INET)
+ conn->ip_version = CURL_IPRESOLVE_V4;
+#ifdef ENABLE_IPV6
+ else if(af == AF_INET6)
+ conn->ip_version = CURL_IPRESOLVE_V6;
+#endif
+
+ rc = Curl_resolv(conn, dev, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_resolver_wait_resolv(conn, &h);
+ conn->ip_version = ipver;
+
+ if(h) {
+ /* convert the resolved address, sizeof myhost >= INET_ADDRSTRLEN */
+ Curl_printable_address(h->addr, myhost, sizeof(myhost));
+ infof(data, "Name '%s' family %i resolved to '%s' family %i\n",
+ dev, af, myhost, h->addr->ai_family);
+ Curl_resolv_unlock(data, h);
+ done = 1;
+ }
+ else {
+ /*
+ * provided dev was no interface (or interfaces are not supported
+ * e.g. solaris) no ip address and no domain we fail here
+ */
+ done = -1;
+ }
+ }
+
+ if(done > 0) {
+#ifdef ENABLE_IPV6
+ /* ipv6 address */
+ if(af == AF_INET6) {
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ char *scope_ptr = strchr(myhost, '%');
+ 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 */
+ si6->sin6_scope_id = atoi(scope_ptr);
+#endif
+ }
+ sizeof_sa = sizeof(struct sockaddr_in6);
+ }
+ else
+#endif
+ /* ipv4 address */
+ if((af == AF_INET) &&
+ (Curl_inet_pton(AF_INET, myhost, &si4->sin_addr) > 0)) {
+ si4->sin_family = AF_INET;
+ si4->sin_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in);
+ }
+ }
+
+ if(done < 1) {
+ failf(data, "Couldn't bind to '%s'", dev);
+ return CURLE_INTERFACE_FAILED;
+ }
+ }
+ else {
+ /* no device was given, prepare sa to match af's needs */
+#ifdef ENABLE_IPV6
+ if(af == AF_INET6) {
+ si6->sin6_family = AF_INET6;
+ si6->sin6_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in6);
+ }
+ else
+#endif
+ if(af == AF_INET) {
+ si4->sin_family = AF_INET;
+ si4->sin_port = htons(port);
+ sizeof_sa = sizeof(struct sockaddr_in);
+ }
+ }
+
+ for(;;) {
+ if(bind(sockfd, sock, sizeof_sa) >= 0) {
+ /* we succeeded to bind */
+ struct Curl_sockaddr_storage add;
+ curl_socklen_t size = sizeof(add);
+ memset(&add, 0, sizeof(struct Curl_sockaddr_storage));
+ if(getsockname(sockfd, (struct sockaddr *) &add, &size) < 0) {
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "getsockname() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return CURLE_INTERFACE_FAILED;
+ }
+ infof(data, "Local port: %hu\n", port);
+ conn->bits.bound = TRUE;
+ return CURLE_OK;
+ }
+
+ if(--portnum > 0) {
+ infof(data, "Bind to local port %hu failed, trying next\n", port);
+ port++; /* try next port */
+ /* We re-use/clobber the port variable here below */
+ if(sock->sa_family == AF_INET)
+ si4->sin_port = ntohs(port);
+#ifdef ENABLE_IPV6
+ else
+ si6->sin6_port = ntohs(port);
+#endif
+ }
+ else
+ break;
+ }
+
+ data->state.os_errno = error = SOCKERRNO;
+ failf(data, "bind failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+
+ return CURLE_INTERFACE_FAILED;
+}
+
+/*
+ * verifyconnect() returns TRUE if the connect really has happened.
+ */
+static bool verifyconnect(curl_socket_t sockfd, int *error)
+{
+ bool rc = TRUE;
+#ifdef SO_ERROR
+ int err = 0;
+ curl_socklen_t errSize = sizeof(err);
+
+#ifdef WIN32
+ /*
+ * In October 2003 we effectively nullified this function on Windows due to
+ * problems with it using all CPU in multi-threaded cases.
+ *
+ * In May 2004, we bring it back to offer more info back on connect failures.
+ * Gisle Vanem could reproduce the former problems with this function, but
+ * could avoid them by adding this SleepEx() call below:
+ *
+ * "I don't have Rational Quantify, but the hint from his post was
+ * ntdll::NtRemoveIoCompletion(). So I'd assume the SleepEx (or maybe
+ * just Sleep(0) would be enough?) would release whatever
+ * mutex/critical-section the ntdll call is waiting on.
+ *
+ * Someone got to verify this on Win-NT 4.0, 2000."
+ */
+
+#ifdef _WIN32_WCE
+ Sleep(0);
+#else
+ SleepEx(0, FALSE);
+#endif
+
+#endif
+
+ if(0 != getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&err, &errSize))
+ err = SOCKERRNO;
+#ifdef _WIN32_WCE
+ /* Old WinCE versions don't support SO_ERROR */
+ if(WSAENOPROTOOPT == err) {
+ SET_SOCKERRNO(0);
+ err = 0;
+ }
+#endif
+#ifdef __minix
+ /* Minix 3.1.x doesn't support getsockopt on UDP sockets */
+ if(EBADIOCTL == err) {
+ SET_SOCKERRNO(0);
+ err = 0;
+ }
+#endif
+ if((0 == err) || (EISCONN == err))
+ /* we are connected, awesome! */
+ rc = TRUE;
+ else
+ /* This wasn't a successful connect */
+ rc = FALSE;
+ if(error)
+ *error = err;
+#else
+ (void)sockfd;
+ if(error)
+ *error = SOCKERRNO;
+#endif
+ return rc;
+}
+
+/* Used within the multi interface. Try next IP address, return TRUE if no
+ more address exists or error */
+static CURLcode trynextip(struct connectdata *conn,
+ int sockindex,
+ bool *connected)
+{
+ curl_socket_t sockfd;
+ Curl_addrinfo *ai;
+
+ /* First clean up after the failed socket.
+ Don't close it yet to ensure that the next IP's socket gets a different
+ file descriptor, which can prevent bugs when the curl_multi_socket_action
+ interface is used with certain select() replacements such as kqueue. */
+ curl_socket_t fd_to_close = conn->sock[sockindex];
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ *connected = FALSE;
+
+ if(sockindex != FIRSTSOCKET) {
+ Curl_closesocket(conn, fd_to_close);
+ return CURLE_COULDNT_CONNECT; /* no next */
+ }
+
+ /* try the next address */
+ ai = conn->ip_addr->ai_next;
+
+ while(ai) {
+ CURLcode res = singleipconnect(conn, ai, &sockfd, connected);
+ if(res)
+ return res;
+ if(sockfd != CURL_SOCKET_BAD) {
+ /* store the new socket descriptor */
+ conn->sock[sockindex] = sockfd;
+ conn->ip_addr = ai;
+ Curl_closesocket(conn, fd_to_close);
+ return CURLE_OK;
+ }
+ ai = ai->ai_next;
+ }
+ Curl_closesocket(conn, fd_to_close);
+ return CURLE_COULDNT_CONNECT;
+}
+
+/* Copies connection info into the session handle to make it available
+ when the session handle is no longer associated with a connection. */
+void Curl_persistconninfo(struct connectdata *conn)
+{
+ memcpy(conn->data->info.conn_primary_ip, conn->primary_ip, MAX_IPADR_LEN);
+ memcpy(conn->data->info.conn_local_ip, conn->local_ip, MAX_IPADR_LEN);
+ conn->data->info.conn_primary_port = conn->primary_port;
+ conn->data->info.conn_local_port = conn->local_port;
+}
+
+/* retrieves ip address and port from a sockaddr structure */
+static bool getaddressinfo(struct sockaddr* sa, char* addr,
+ long* port)
+{
+ unsigned short us_port;
+ struct sockaddr_in* si = NULL;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6* si6 = NULL;
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+ struct sockaddr_un* su = NULL;
+#endif
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ si = (struct sockaddr_in*) sa;
+ if(Curl_inet_ntop(sa->sa_family, &si->sin_addr,
+ addr, MAX_IPADR_LEN)) {
+ us_port = ntohs(si->sin_port);
+ *port = us_port;
+ return TRUE;
+ }
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ si6 = (struct sockaddr_in6*)sa;
+ if(Curl_inet_ntop(sa->sa_family, &si6->sin6_addr,
+ addr, MAX_IPADR_LEN)) {
+ us_port = ntohs(si6->sin6_port);
+ *port = us_port;
+ return TRUE;
+ }
+ break;
+#endif
+#if defined(HAVE_SYS_UN_H) && defined(AF_UNIX)
+ case AF_UNIX:
+ su = (struct sockaddr_un*)sa;
+ snprintf(addr, MAX_IPADR_LEN, "%s", su->sun_path);
+ *port = 0;
+ return TRUE;
+#endif
+ default:
+ break;
+ }
+
+ addr[0] = '\0';
+ *port = 0;
+
+ return FALSE;
+}
+
+/* retrieves the start/end point information of a socket of an established
+ connection */
+void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd)
+{
+ int error;
+ curl_socklen_t len;
+ struct Curl_sockaddr_storage ssrem;
+ struct Curl_sockaddr_storage ssloc;
+ struct SessionHandle *data = conn->data;
+
+ if(!conn->bits.reuse) {
+
+ len = sizeof(struct Curl_sockaddr_storage);
+ if(getpeername(sockfd, (struct sockaddr*) &ssrem, &len)) {
+ error = SOCKERRNO;
+ failf(data, "getpeername() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ len = sizeof(struct Curl_sockaddr_storage);
+ if(getsockname(sockfd, (struct sockaddr*) &ssloc, &len)) {
+ error = SOCKERRNO;
+ failf(data, "getsockname() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ if(!getaddressinfo((struct sockaddr*)&ssrem,
+ conn->primary_ip, &conn->primary_port)) {
+ error = ERRNO;
+ failf(data, "ssrem inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ if(!getaddressinfo((struct sockaddr*)&ssloc,
+ conn->local_ip, &conn->local_port)) {
+ error = ERRNO;
+ failf(data, "ssloc inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ return;
+ }
+
+ }
+
+ /* persist connection info in session handle */
+ Curl_persistconninfo(conn);
+}
+
+/*
+ * Curl_is_connected() checks if the socket has connected.
+ */
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+ int sockindex,
+ bool *connected)
+{
+ struct SessionHandle *data = conn->data;
+ CURLcode code = CURLE_OK;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long allow = DEFAULT_CONNECT_TIMEOUT;
+ int error = 0;
+ struct timeval now;
+ enum chkconn_t chk;
+
+ DEBUGASSERT(sockindex >= FIRSTSOCKET && sockindex <= SECONDARYSOCKET);
+
+ *connected = FALSE; /* a very negative world view is best */
+
+ if(conn->bits.tcpconnect[sockindex]) {
+ /* we are connected already! */
+ *connected = TRUE;
+ return CURLE_OK;
+ }
+
+ now = Curl_tvnow();
+
+ /* figure out how long time we have left to connect */
+ allow = Curl_timeleft(data, &now, TRUE);
+
+ if(allow < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* check socket for connect */
+ chk = checkconnect(sockfd);
+ if(CHKCONN_IDLE == chk) {
+ if(curlx_tvdiff(now, conn->connecttime) >= conn->timeoutms_per_addr) {
+ infof(data, "After %ldms connect time, move on!\n",
+ conn->timeoutms_per_addr);
+ goto next;
+ }
+
+ /* not an error, but also no connection yet */
+ return code;
+ }
+
+ if(CHKCONN_CONNECTED == chk) {
+ if(verifyconnect(sockfd, &error)) {
+ /* we are connected with TCP, awesome! */
+
+ /* see if we need to do any proxy magic first once we connected */
+ code = Curl_connected_proxy(conn);
+ if(code)
+ return code;
+
+ conn->bits.tcpconnect[sockindex] = TRUE;
+
+ *connected = TRUE;
+ if(sockindex == FIRSTSOCKET)
+ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+ Curl_verboseconnect(conn);
+ Curl_updateconninfo(conn, sockfd);
+
+ return CURLE_OK;
+ }
+ /* nope, not connected for real */
+ }
+ else {
+ /* nope, not connected */
+ if(CHKCONN_FDSET_ERROR == chk) {
+ (void)verifyconnect(sockfd, &error);
+ infof(data, "%s\n",Curl_strerror(conn, error));
+ }
+ else
+ infof(data, "Connection failed\n");
+ }
+
+ /*
+ * The connection failed here, we should attempt to connect to the "next
+ * address" for the given host. But first remember the latest error.
+ */
+ if(error) {
+ data->state.os_errno = error;
+ SET_SOCKERRNO(error);
+ }
+ next:
+
+ conn->timeoutms_per_addr = conn->ip_addr->ai_next == NULL ?
+ allow : allow / 2;
+ code = trynextip(conn, sockindex, connected);
+
+ if(code) {
+ error = SOCKERRNO;
+ data->state.os_errno = error;
+ failf(data, "Failed connect to %s:%ld; %s",
+ conn->host.name, conn->port, Curl_strerror(conn, error));
+ }
+
+ return code;
+}
+
+static void tcpnodelay(struct connectdata *conn,
+ curl_socket_t sockfd)
+{
+#ifdef TCP_NODELAY
+ struct SessionHandle *data= conn->data;
+ curl_socklen_t onoff = (curl_socklen_t) data->set.tcp_nodelay;
+ int level = IPPROTO_TCP;
+
+#if 0
+ /* The use of getprotobyname() is disabled since it isn't thread-safe on
+ numerous systems. On these getprotobyname_r() should be used instead, but
+ that exists in at least one 4 arg version and one 5 arg version, and
+ since the proto number rarely changes anyway we now just use the hard
+ coded number. The "proper" fix would need a configure check for the
+ correct function much in the same style the gethostbyname_r versions are
+ detected. */
+ struct protoent *pe = getprotobyname("tcp");
+ if(pe)
+ level = pe->p_proto;
+#endif
+
+ if(setsockopt(sockfd, level, TCP_NODELAY, (void *)&onoff,
+ sizeof(onoff)) < 0)
+ infof(data, "Could not set TCP_NODELAY: %s\n",
+ Curl_strerror(conn, SOCKERRNO));
+ else
+ infof(data,"TCP_NODELAY set\n");
+#else
+ (void)conn;
+ (void)sockfd;
+#endif
+}
+
+#ifdef SO_NOSIGPIPE
+/* The preferred method on Mac OS X (10.2 and later) to prevent SIGPIPEs when
+ sending data to a dead peer (instead of relying on the 4th argument to send
+ being MSG_NOSIGNAL). Possibly also existing and in use on other BSD
+ systems? */
+static void nosigpipe(struct connectdata *conn,
+ curl_socket_t sockfd)
+{
+ struct SessionHandle *data= conn->data;
+ int onoff = 1;
+ if(setsockopt(sockfd, SOL_SOCKET, SO_NOSIGPIPE, (void *)&onoff,
+ sizeof(onoff)) < 0)
+ infof(data, "Could not set SO_NOSIGPIPE: %s\n",
+ Curl_strerror(conn, SOCKERRNO));
+}
+#else
+#define nosigpipe(x,y) Curl_nop_stmt
+#endif
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+ experience slow performance when you copy data to a TCP server.
+
+ http://support.microsoft.com/kb/823764
+
+ Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+ Buffer Size
+
+ The problem described in this knowledge-base is applied only to pre-Vista
+ Windows. Following function trying to detect OS version and skips
+ SO_SNDBUF adjustment for Windows Vista and above.
+*/
+#define DETECT_OS_NONE 0
+#define DETECT_OS_PREVISTA 1
+#define DETECT_OS_VISTA_OR_LATER 2
+
+void Curl_sndbufset(curl_socket_t sockfd)
+{
+ int val = CURL_MAX_WRITE_SIZE + 32;
+ int curval = 0;
+ int curlen = sizeof(curval);
+
+ OSVERSIONINFO osver;
+ static int detectOsState = DETECT_OS_NONE;
+
+ if(detectOsState == DETECT_OS_NONE) {
+ memset(&osver, 0, sizeof(osver));
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ detectOsState = DETECT_OS_PREVISTA;
+ if(GetVersionEx(&osver)) {
+ if(osver.dwMajorVersion >= 6)
+ detectOsState = DETECT_OS_VISTA_OR_LATER;
+ }
+ }
+ if(detectOsState == DETECT_OS_VISTA_OR_LATER)
+ return;
+
+ if(getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (char *)&curval, &curlen) == 0)
+ if(curval > val)
+ return;
+
+ setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, (const char *)&val, sizeof(val));
+}
+#endif
+
+
+/*
+ * singleipconnect()
+ *
+ * Note that even on connect fail it returns CURLE_OK, but with 'sock' set to
+ * CURL_SOCKET_BAD. Other errors will however return proper errors.
+ *
+ * singleipconnect() connects to the given IP only, and it may return without
+ * having connected.
+ */
+static CURLcode
+singleipconnect(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ curl_socket_t *sockp,
+ bool *connected)
+{
+ struct Curl_sockaddr_ex addr;
+ int rc;
+ int error = 0;
+ bool isconnected = FALSE;
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd;
+ CURLcode res = CURLE_OK;
+
+ *sockp = CURL_SOCKET_BAD;
+ *connected = FALSE; /* default is not connected */
+
+ res = Curl_socket(conn, ai, &addr, &sockfd);
+ if(res)
+ /* Failed to create the socket, but still return OK since we signal the
+ lack of socket as well. This allows the parent function to keep looping
+ over alternative addresses/socket families etc. */
+ return CURLE_OK;
+
+ /* store remote address and port used in this connection attempt */
+ if(!getaddressinfo((struct sockaddr*)&addr.sa_addr,
+ conn->primary_ip, &conn->primary_port)) {
+ /* malformed address or bug in inet_ntop, try next address */
+ error = ERRNO;
+ failf(data, "sa_addr inet_ntop() failed with errno %d: %s",
+ error, Curl_strerror(conn, error));
+ Curl_closesocket(conn, sockfd);
+ return CURLE_OK;
+ }
+ memcpy(conn->ip_addr_str, conn->primary_ip, MAX_IPADR_LEN);
+ infof(data, " Trying %s...\n", conn->ip_addr_str);
+
+ Curl_persistconninfo(conn);
+
+ if(data->set.tcp_nodelay)
+ tcpnodelay(conn, sockfd);
+
+ nosigpipe(conn, sockfd);
+
+ Curl_sndbufset(sockfd);
+
+ if(data->set.tcp_keepalive)
+ tcpkeepalive(data, sockfd);
+
+ if(data->set.fsockopt) {
+ /* activate callback for setting socket options */
+ error = data->set.fsockopt(data->set.sockopt_client,
+ sockfd,
+ CURLSOCKTYPE_IPCXN);
+
+ if(error == CURL_SOCKOPT_ALREADY_CONNECTED)
+ isconnected = TRUE;
+ else if(error) {
+ Curl_closesocket(conn, sockfd); /* close the socket and bail out */
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+
+ /* possibly bind the local end to an IP, interface or port */
+ res = bindlocal(conn, sockfd, addr.family);
+ if(res) {
+ Curl_closesocket(conn, sockfd); /* close socket and bail out */
+ if(res == CURLE_UNSUPPORTED_PROTOCOL) {
+ /* The address family is not supported on this interface.
+ We can continue trying addresses */
+ return CURLE_OK;
+ }
+ return res;
+ }
+
+ /* set socket non-blocking */
+ curlx_nonblock(sockfd, TRUE);
+
+ conn->connecttime = Curl_tvnow();
+ if(conn->num_addr > 1)
+ Curl_expire(data, conn->timeoutms_per_addr);
+
+ /* Connect TCP sockets, bind UDP */
+ if(!isconnected && (conn->socktype == SOCK_STREAM)) {
+ rc = connect(sockfd, &addr.sa_addr, addr.addrlen);
+ if(-1 == rc)
+ error = SOCKERRNO;
+ }
+ else {
+ *sockp = sockfd;
+ return CURLE_OK;
+ }
+
+#ifdef ENABLE_IPV6
+ conn->bits.ipv6 = (addr.family == AF_INET6)?TRUE:FALSE;
+#endif
+
+ if(-1 == rc) {
+ switch (error) {
+ case EINPROGRESS:
+ case EWOULDBLOCK:
+#if defined(EAGAIN)
+#if (EAGAIN) != (EWOULDBLOCK)
+ /* On some platforms EAGAIN and EWOULDBLOCK are the
+ * same value, and on others they are different, hence
+ * the odd #if
+ */
+ case EAGAIN:
+#endif
+#endif
+ *sockp = sockfd;
+ return CURLE_OK;
+
+ default:
+ /* unknown error, fallthrough and try another address! */
+ failf(data, "Failed to connect to %s: %s",
+ conn->ip_addr_str, Curl_strerror(conn,error));
+ data->state.os_errno = error;
+
+ /* connect failed */
+ Curl_closesocket(conn, sockfd);
+
+ break;
+ }
+ }
+ else
+ *sockp = sockfd;
+
+ return CURLE_OK;
+}
+
+/*
+ * TCP connect to the given host with timeout, proxy or remote doesn't matter.
+ * There might be more than one IP address to try out. Fill in the passed
+ * pointer with the connected socket.
+ */
+
+CURLcode Curl_connecthost(struct connectdata *conn, /* context */
+ const struct Curl_dns_entry *remotehost,
+ curl_socket_t *sockconn, /* the connected socket */
+ Curl_addrinfo **addr, /* the one we used */
+ bool *connected) /* really connected? */
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = CURL_SOCKET_BAD;
+ Curl_addrinfo *ai;
+ Curl_addrinfo *curr_addr;
+
+ struct timeval after;
+ struct timeval before = Curl_tvnow();
+
+ /*************************************************************
+ * Figure out what maximum time we have left
+ *************************************************************/
+ long timeout_ms;
+
+ DEBUGASSERT(sockconn);
+ *connected = FALSE; /* default to not connected */
+
+ /* get the timeout left */
+ timeout_ms = Curl_timeleft(data, &before, TRUE);
+
+ if(timeout_ms < 0) {
+ /* a precaution, no need to continue if time already is up */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ conn->num_addr = Curl_num_addresses(remotehost->addr);
+
+ ai = remotehost->addr;
+
+ /* Below is the loop that attempts to connect to all IP-addresses we
+ * know for the given host. One by one until one IP succeeds.
+ */
+
+ /*
+ * Connecting with a Curl_addrinfo chain
+ */
+ for(curr_addr = ai; curr_addr; curr_addr = curr_addr->ai_next) {
+ CURLcode res;
+
+ /* Max time for the next address */
+ conn->timeoutms_per_addr = curr_addr->ai_next == NULL ?
+ timeout_ms : timeout_ms / 2;
+
+ /* start connecting to the IP curr_addr points to */
+ res = singleipconnect(conn, curr_addr,
+ &sockfd, connected);
+ if(res)
+ return res;
+
+ if(sockfd != CURL_SOCKET_BAD)
+ break;
+
+ /* get a new timeout for next attempt */
+ after = Curl_tvnow();
+ timeout_ms -= Curl_tvdiff(after, before);
+ if(timeout_ms < 0) {
+ failf(data, "connect() timed out!");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ before = after;
+ } /* end of connect-to-each-address loop */
+
+ *sockconn = sockfd; /* the socket descriptor we've connected */
+
+ if(sockfd == CURL_SOCKET_BAD) {
+ /* no good connect was made */
+ 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;
+ }
+
+ /* leave the socket in non-blocking mode */
+
+ /* store the address we use */
+ if(addr)
+ *addr = curr_addr;
+
+ data->info.numconnects++; /* to track the number of connections made */
+
+ return CURLE_OK;
+}
+
+struct connfind {
+ struct connectdata *tofind;
+ bool found;
+};
+
+static int conn_is_conn(struct connectdata *conn, void *param)
+{
+ struct connfind *f = (struct connfind *)param;
+ if(conn == f->tofind) {
+ f->found = TRUE;
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given SessionHandle.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
+ struct connectdata **connp)
+{
+ curl_socket_t sockfd;
+
+ DEBUGASSERT(data);
+
+ /* this only works for an easy handle that has been used for
+ curl_easy_perform()! */
+ if(data->state.lastconnect && data->multi_easy) {
+ struct connectdata *c = data->state.lastconnect;
+ struct connfind find;
+ find.tofind = data->state.lastconnect;
+ find.found = FALSE;
+
+ Curl_conncache_foreach(data->multi_easy->conn_cache, &find, conn_is_conn);
+
+ if(!find.found) {
+ data->state.lastconnect = NULL;
+ return CURL_SOCKET_BAD;
+ }
+
+ if(connp)
+ /* only store this if the caller cares for it */
+ *connp = c;
+ sockfd = c->sock[FIRSTSOCKET];
+ /* we have a socket connected, let's determine if the server shut down */
+ /* determine if ssl */
+ if(c->ssl[FIRSTSOCKET].use) {
+ /* use the SSL context */
+ if(!Curl_ssl_check_cxn(c))
+ return CURL_SOCKET_BAD; /* FIN received */
+ }
+/* Minix 3.1 doesn't support any flags on recv; just assume socket is OK */
+#ifdef MSG_PEEK
+ else {
+ /* use the socket */
+ char buf;
+ if(recv((RECV_TYPE_ARG1)c->sock[FIRSTSOCKET], (RECV_TYPE_ARG2)&buf,
+ (RECV_TYPE_ARG3)1, (RECV_TYPE_ARG4)MSG_PEEK) == 0) {
+ return CURL_SOCKET_BAD; /* FIN received */
+ }
+ }
+#endif
+ }
+ else
+ return CURL_SOCKET_BAD;
+
+ return sockfd;
+}
+
+/*
+ * Close a socket.
+ *
+ * 'conn' can be NULL, beware!
+ */
+int Curl_closesocket(struct connectdata *conn,
+ curl_socket_t sock)
+{
+ if(conn && conn->fclosesocket) {
+ if((sock == conn->sock[SECONDARYSOCKET]) &&
+ conn->sock_accepted[SECONDARYSOCKET])
+ /* if this socket matches the second socket, and that was created with
+ accept, then we MUST NOT call the callback but clear the accepted
+ status */
+ conn->sock_accepted[SECONDARYSOCKET] = FALSE;
+ else
+ return conn->fclosesocket(conn->closesocket_client, sock);
+ }
+ sclose(sock);
+
+ if(conn)
+ /* tell the multi-socket code about this */
+ Curl_multi_closed(conn, sock);
+
+ return 0;
+}
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * 'addr' should be a pointer to the correct struct to get data back, or NULL.
+ * 'sockfd' must be a pointer to a socket descriptor.
+ *
+ * If the open socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ struct Curl_sockaddr_ex *addr,
+ curl_socket_t *sockfd)
+{
+ struct SessionHandle *data = conn->data;
+ struct Curl_sockaddr_ex dummy;
+
+ if(!addr)
+ /* if the caller doesn't want info back, use a local temp copy */
+ addr = &dummy;
+
+ /*
+ * The Curl_sockaddr_ex structure is basically libcurl's external API
+ * curl_sockaddr structure with enough space available to directly hold
+ * any protocol-specific address structures. The variable declared here
+ * will be used to pass / receive data to/from the fopensocket callback
+ * if this has been set, before that, it is initialized from parameters.
+ */
+
+ addr->family = ai->ai_family;
+ addr->socktype = conn->socktype;
+ addr->protocol = conn->socktype==SOCK_DGRAM?IPPROTO_UDP:ai->ai_protocol;
+ addr->addrlen = ai->ai_addrlen;
+
+ if(addr->addrlen > sizeof(struct Curl_sockaddr_storage))
+ addr->addrlen = sizeof(struct Curl_sockaddr_storage);
+ memcpy(&addr->sa_addr, ai->ai_addr, addr->addrlen);
+
+ if(data->set.fopensocket)
+ /*
+ * If the opensocket callback is set, all the destination address
+ * information is passed to the callback. Depending on this information the
+ * callback may opt to abort the connection, this is indicated returning
+ * CURL_SOCKET_BAD; otherwise it will return a not-connected socket. When
+ * the callback returns a valid socket the destination address information
+ * might have been changed and this 'new' address will actually be used
+ * here to connect.
+ */
+ *sockfd = data->set.fopensocket(data->set.opensocket_client,
+ CURLSOCKTYPE_IPCXN,
+ (struct curl_sockaddr *)addr);
+ else
+ /* opensocket callback not set, so simply create the socket now */
+ *sockfd = socket(addr->family, addr->socktype, addr->protocol);
+
+ if(*sockfd == CURL_SOCKET_BAD)
+ /* no socket, no connection */
+ return CURLE_COULDNT_CONNECT;
+
+#if defined(ENABLE_IPV6) && defined(HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID)
+ if(conn->scope && (addr->family == AF_INET6)) {
+ struct sockaddr_in6 * const sa6 = (void *)&addr->sa_addr;
+ sa6->sin6_scope_id = conn->scope;
+ }
+#endif
+
+ return CURLE_OK;
+
+}
diff --git a/libs/libcurl/src/connect.h b/libs/libcurl/src/connect.h
new file mode 100644
index 0000000000..ab98002894
--- /dev/null
+++ b/libs/libcurl/src/connect.h
@@ -0,0 +1,107 @@
+#ifndef HEADER_CURL_CONNECT_H
+#define HEADER_CURL_CONNECT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "nonblock.h" /* for curlx_nonblock(), formerly Curl_nonblock() */
+#include "sockaddr.h"
+
+CURLcode Curl_is_connected(struct connectdata *conn,
+ int sockindex,
+ bool *connected);
+
+CURLcode Curl_connecthost(struct connectdata *conn,
+ const struct Curl_dns_entry *host, /* connect to
+ this */
+ curl_socket_t *sockconn, /* not set if error */
+ Curl_addrinfo **addr, /* the one we used */
+ bool *connected); /* truly connected? */
+
+/* generic function that returns how much time there's left to run, according
+ to the timeouts set */
+long Curl_timeleft(struct SessionHandle *data,
+ struct timeval *nowp,
+ bool duringconnect);
+
+#define DEFAULT_CONNECT_TIMEOUT 300000 /* milliseconds == five minutes */
+
+/*
+ * Used to extract socket and connectdata struct for the most recent
+ * transfer on the given SessionHandle.
+ *
+ * The returned socket will be CURL_SOCKET_BAD in case of failure!
+ */
+curl_socket_t Curl_getconnectinfo(struct SessionHandle *data,
+ struct connectdata **connp);
+
+#ifdef USE_WINSOCK
+/* When you run a program that uses the Windows Sockets API, you may
+ experience slow performance when you copy data to a TCP server.
+
+ http://support.microsoft.com/kb/823764
+
+ Work-around: Make the Socket Send Buffer Size Larger Than the Program Send
+ Buffer Size
+
+*/
+void Curl_sndbufset(curl_socket_t sockfd);
+#else
+#define Curl_sndbufset(y) Curl_nop_stmt
+#endif
+
+void Curl_updateconninfo(struct connectdata *conn, curl_socket_t sockfd);
+void Curl_persistconninfo(struct connectdata *conn);
+int Curl_closesocket(struct connectdata *conn, curl_socket_t sock);
+
+/*
+ * The Curl_sockaddr_ex structure is basically libcurl's external API
+ * curl_sockaddr structure with enough space available to directly hold any
+ * protocol-specific address structures. The variable declared here will be
+ * used to pass / receive data to/from the fopensocket callback if this has
+ * been set, before that, it is initialized from parameters.
+ */
+struct Curl_sockaddr_ex {
+ int family;
+ int socktype;
+ int protocol;
+ unsigned int addrlen;
+ union {
+ struct sockaddr addr;
+ struct Curl_sockaddr_storage buff;
+ } _sa_ex_u;
+};
+#define sa_addr _sa_ex_u.addr
+
+/*
+ * Create a socket based on info from 'conn' and 'ai'.
+ *
+ * Fill in 'addr' and 'sockfd' accordingly if OK is returned. If the open
+ * socket callback is set, used that!
+ *
+ */
+CURLcode Curl_socket(struct connectdata *conn,
+ const Curl_addrinfo *ai,
+ struct Curl_sockaddr_ex *addr,
+ curl_socket_t *sockfd);
+
+#endif /* HEADER_CURL_CONNECT_H */
diff --git a/libs/libcurl/src/content_encoding.c b/libs/libcurl/src/content_encoding.c
new file mode 100644
index 0000000000..c68e6e5f52
--- /dev/null
+++ b/libs/libcurl/src/content_encoding.c
@@ -0,0 +1,435 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 HAVE_LIBZ
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "content_encoding.h"
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+/* Comment this out if zlib is always going to be at least ver. 1.2.0.4
+ (doing so will reduce code size slightly). */
+#define OLD_ZLIB_SUPPORT 1
+
+#define DSIZ CURL_MAX_WRITE_SIZE /* buffer size for decompressed data */
+
+#define GZIP_MAGIC_0 0x1f
+#define GZIP_MAGIC_1 0x8b
+
+/* gzip flag byte */
+#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */
+#define HEAD_CRC 0x02 /* bit 1 set: header CRC present */
+#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */
+#define ORIG_NAME 0x08 /* bit 3 set: original file name present */
+#define COMMENT 0x10 /* bit 4 set: file comment present */
+#define RESERVED 0xE0 /* bits 5..7: reserved */
+
+static voidpf
+zalloc_cb(voidpf opaque, unsigned int items, unsigned int size)
+{
+ (void) opaque;
+ /* not a typo, keep it calloc() */
+ return (voidpf) calloc(items, size);
+}
+
+static void
+zfree_cb(voidpf opaque, voidpf ptr)
+{
+ (void) opaque;
+ free(ptr);
+}
+
+static CURLcode
+process_zlib_error(struct connectdata *conn, z_stream *z)
+{
+ struct SessionHandle *data = conn->data;
+ if(z->msg)
+ failf (data, "Error while processing content unencoding: %s",
+ z->msg);
+ else
+ failf (data, "Error while processing content unencoding: "
+ "Unknown failure within decompression software.");
+
+ return CURLE_BAD_CONTENT_ENCODING;
+}
+
+static CURLcode
+exit_zlib(z_stream *z, zlibInitState *zlib_init, CURLcode result)
+{
+ inflateEnd(z);
+ *zlib_init = ZLIB_UNINIT;
+ return result;
+}
+
+static CURLcode
+inflate_stream(struct connectdata *conn,
+ struct SingleRequest *k)
+{
+ int allow_restart = 1;
+ z_stream *z = &k->z; /* zlib state structure */
+ uInt nread = z->avail_in;
+ Bytef *orig_in = z->next_in;
+ int status; /* zlib status */
+ CURLcode result = CURLE_OK; /* Curl_client_write status */
+ char *decomp; /* Put the decompressed data here. */
+
+ /* Dynamically allocate a buffer for decompression because it's uncommonly
+ large to hold on the stack */
+ decomp = malloc(DSIZ);
+ if(decomp == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+
+ /* because the buffer size is fixed, iteratively decompress and transfer to
+ the client via client_write. */
+ for(;;) {
+ /* (re)set buffer for decompressed output for every iteration */
+ z->next_out = (Bytef *)decomp;
+ z->avail_out = DSIZ;
+
+ status = inflate(z, Z_SYNC_FLUSH);
+ if(status == Z_OK || status == Z_STREAM_END) {
+ allow_restart = 0;
+ if((DSIZ - z->avail_out) && (!k->ignorebody)) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, decomp,
+ DSIZ - z->avail_out);
+ /* if !CURLE_OK, clean up, return */
+ if(result) {
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, result);
+ }
+ }
+
+ /* Done? clean up, return */
+ if(status == Z_STREAM_END) {
+ free(decomp);
+ if(inflateEnd(z) == Z_OK)
+ return exit_zlib(z, &k->zlib_init, result);
+ else
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ /* Done with these bytes, exit */
+
+ /* status is always Z_OK at this point! */
+ if(z->avail_in == 0) {
+ free(decomp);
+ return result;
+ }
+ }
+ else if(allow_restart && status == Z_DATA_ERROR) {
+ /* some servers seem to not generate zlib headers, so this is an attempt
+ to fix and continue anyway */
+
+ (void) inflateEnd(z); /* don't care about the return code */
+ if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+ z->next_in = orig_in;
+ z->avail_in = nread;
+ allow_restart = 0;
+ continue;
+ }
+ else { /* Error; exit loop, handle below */
+ free(decomp);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+ }
+ /* Will never get here */
+}
+
+CURLcode
+Curl_unencode_deflate_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread)
+{
+ z_stream *z = &k->z; /* zlib state structure */
+
+ /* Initialize zlib? */
+ if(k->zlib_init == ZLIB_UNINIT) {
+ memset(z, 0, sizeof(z_stream));
+ z->zalloc = (alloc_func)zalloc_cb;
+ z->zfree = (free_func)zfree_cb;
+
+ if(inflateInit(z) != Z_OK)
+ return process_zlib_error(conn, z);
+ k->zlib_init = ZLIB_INIT;
+ }
+
+ /* Set the compressed input when this function is called */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+
+ /* Now uncompress the data */
+ return inflate_stream(conn, k);
+}
+
+#ifdef OLD_ZLIB_SUPPORT
+/* Skip over the gzip header */
+static enum {
+ GZIP_OK,
+ GZIP_BAD,
+ GZIP_UNDERFLOW
+} check_gzip_header(unsigned char const *data, ssize_t len, ssize_t *headerlen)
+{
+ int method, flags;
+ const ssize_t totallen = len;
+
+ /* The shortest header is 10 bytes */
+ if(len < 10)
+ return GZIP_UNDERFLOW;
+
+ if((data[0] != GZIP_MAGIC_0) || (data[1] != GZIP_MAGIC_1))
+ return GZIP_BAD;
+
+ method = data[2];
+ flags = data[3];
+
+ if(method != Z_DEFLATED || (flags & RESERVED) != 0) {
+ /* Can't handle this compression method or unknown flag */
+ return GZIP_BAD;
+ }
+
+ /* Skip over time, xflags, OS code and all previous bytes */
+ len -= 10;
+ data += 10;
+
+ if(flags & EXTRA_FIELD) {
+ ssize_t extra_len;
+
+ if(len < 2)
+ return GZIP_UNDERFLOW;
+
+ extra_len = (data[1] << 8) | data[0];
+
+ if(len < (extra_len+2))
+ return GZIP_UNDERFLOW;
+
+ len -= (extra_len + 2);
+ data += (extra_len + 2);
+ }
+
+ if(flags & ORIG_NAME) {
+ /* Skip over NUL-terminated file name */
+ while(len && *data) {
+ --len;
+ ++data;
+ }
+ if(!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ ++data;
+ }
+
+ if(flags & COMMENT) {
+ /* Skip over NUL-terminated comment */
+ while(len && *data) {
+ --len;
+ ++data;
+ }
+ if(!len || *data)
+ return GZIP_UNDERFLOW;
+
+ /* Skip over the NUL */
+ --len;
+ }
+
+ if(flags & HEAD_CRC) {
+ if(len < 2)
+ return GZIP_UNDERFLOW;
+
+ len -= 2;
+ }
+
+ *headerlen = totallen - len;
+ return GZIP_OK;
+}
+#endif
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread)
+{
+ z_stream *z = &k->z; /* zlib state structure */
+
+ /* Initialize zlib? */
+ if(k->zlib_init == ZLIB_UNINIT) {
+ memset(z, 0, sizeof(z_stream));
+ z->zalloc = (alloc_func)zalloc_cb;
+ z->zfree = (free_func)zfree_cb;
+
+ if(strcmp(zlibVersion(), "1.2.0.4") >= 0) {
+ /* zlib ver. >= 1.2.0.4 supports transparent gzip decompressing */
+ if(inflateInit2(z, MAX_WBITS+32) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ k->zlib_init = ZLIB_INIT_GZIP; /* Transparent gzip decompress state */
+ }
+ else {
+ /* we must parse the gzip header ourselves */
+ if(inflateInit2(z, -MAX_WBITS) != Z_OK) {
+ return process_zlib_error(conn, z);
+ }
+ k->zlib_init = ZLIB_INIT; /* Initial call state */
+ }
+ }
+
+ if(k->zlib_init == ZLIB_INIT_GZIP) {
+ /* Let zlib handle the gzip decompression entirely */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+ /* Now uncompress the data */
+ return inflate_stream(conn, k);
+ }
+
+#ifndef OLD_ZLIB_SUPPORT
+ /* Support for old zlib versions is compiled away and we are running with
+ an old version, so return an error. */
+ return exit_zlib(z, &k->zlib_init, CURLE_FUNCTION_NOT_FOUND);
+
+#else
+ /* This next mess is to get around the potential case where there isn't
+ * enough data passed in to skip over the gzip header. If that happens, we
+ * malloc a block and copy what we have then wait for the next call. If
+ * there still isn't enough (this is definitely a worst-case scenario), we
+ * make the block bigger, copy the next part in and keep waiting.
+ *
+ * This is only required with zlib versions < 1.2.0.4 as newer versions
+ * can handle the gzip header themselves.
+ */
+
+ switch (k->zlib_init) {
+ /* Skip over gzip header? */
+ case ZLIB_INIT:
+ {
+ /* Initial call state */
+ ssize_t hlen;
+
+ switch (check_gzip_header((unsigned char *)k->str, nread, &hlen)) {
+ case GZIP_OK:
+ z->next_in = (Bytef *)k->str + hlen;
+ z->avail_in = (uInt)(nread - hlen);
+ k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We need more data so we can find the end of the gzip header. It's
+ * possible that the memory block we malloc here will never be freed if
+ * the transfer abruptly aborts after this point. Since it's unlikely
+ * that circumstances will be right for this code path to be followed in
+ * the first place, and it's even more unlikely for a transfer to fail
+ * immediately afterwards, it should seldom be a problem.
+ */
+ z->avail_in = (uInt)nread;
+ z->next_in = malloc(z->avail_in);
+ if(z->next_in == NULL) {
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ memcpy(z->next_in, k->str, z->avail_in);
+ k->zlib_init = ZLIB_GZIP_HEADER; /* Need more gzip header data state */
+ /* We don't have any data to inflate yet */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ }
+ break;
+
+ case ZLIB_GZIP_HEADER:
+ {
+ /* Need more gzip header data state */
+ ssize_t hlen;
+ unsigned char *oldblock = z->next_in;
+
+ z->avail_in += (uInt)nread;
+ z->next_in = realloc(z->next_in, z->avail_in);
+ if(z->next_in == NULL) {
+ free(oldblock);
+ return exit_zlib(z, &k->zlib_init, CURLE_OUT_OF_MEMORY);
+ }
+ /* Append the new block of data to the previous one */
+ memcpy(z->next_in + z->avail_in - nread, k->str, nread);
+
+ switch (check_gzip_header(z->next_in, z->avail_in, &hlen)) {
+ case GZIP_OK:
+ /* This is the zlib stream data */
+ free(z->next_in);
+ /* Don't point into the malloced block since we just freed it */
+ z->next_in = (Bytef *)k->str + hlen + nread - z->avail_in;
+ z->avail_in = (uInt)(z->avail_in - hlen);
+ k->zlib_init = ZLIB_GZIP_INFLATING; /* Inflating stream state */
+ break;
+
+ case GZIP_UNDERFLOW:
+ /* We still don't have any data to inflate! */
+ return CURLE_OK;
+
+ case GZIP_BAD:
+ default:
+ free(z->next_in);
+ return exit_zlib(z, &k->zlib_init, process_zlib_error(conn, z));
+ }
+
+ }
+ break;
+
+ case ZLIB_GZIP_INFLATING:
+ default:
+ /* Inflating stream state */
+ z->next_in = (Bytef *)k->str;
+ z->avail_in = (uInt)nread;
+ break;
+ }
+
+ if(z->avail_in == 0) {
+ /* We don't have any data to inflate; wait until next time */
+ return CURLE_OK;
+ }
+
+ /* We've parsed the header, now uncompress the data */
+ return inflate_stream(conn, k);
+#endif
+}
+
+void Curl_unencode_cleanup(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ struct SingleRequest *k = &data->req;
+ z_stream *z = &k->z;
+ if(k->zlib_init != ZLIB_UNINIT)
+ (void) exit_zlib(z, &k->zlib_init, CURLE_OK);
+}
+
+#endif /* HAVE_LIBZ */
diff --git a/libs/libcurl/src/content_encoding.h b/libs/libcurl/src/content_encoding.h
new file mode 100644
index 0000000000..501f6c8ceb
--- /dev/null
+++ b/libs/libcurl/src/content_encoding.h
@@ -0,0 +1,48 @@
+#ifndef HEADER_CURL_CONTENT_ENCODING_H
+#define HEADER_CURL_CONTENT_ENCODING_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+/*
+ * Comma-separated list all supported Content-Encodings ('identity' is implied)
+ */
+#ifdef HAVE_LIBZ
+#define ALL_CONTENT_ENCODINGS "deflate, gzip"
+/* force a cleanup */
+void Curl_unencode_cleanup(struct connectdata *conn);
+#else
+#define ALL_CONTENT_ENCODINGS "identity"
+#define Curl_unencode_cleanup(x) Curl_nop_stmt
+#endif
+
+CURLcode Curl_unencode_deflate_write(struct connectdata *conn,
+ struct SingleRequest *req,
+ ssize_t nread);
+
+CURLcode
+Curl_unencode_gzip_write(struct connectdata *conn,
+ struct SingleRequest *k,
+ ssize_t nread);
+
+
+#endif /* HEADER_CURL_CONTENT_ENCODING_H */
diff --git a/libs/libcurl/src/cookie.c b/libs/libcurl/src/cookie.c
new file mode 100644
index 0000000000..9deeb1ac49
--- /dev/null
+++ b/libs/libcurl/src/cookie.c
@@ -0,0 +1,1319 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/***
+
+
+RECEIVING COOKIE INFORMATION
+============================
+
+struct CookieInfo *cookie_init(char *file);
+
+ Inits a cookie struct to store data in a local file. This is always
+ called before any cookies are set.
+
+int cookies_set(struct CookieInfo *cookie, char *cookie_line);
+
+ The 'cookie_line' parameter is a full "Set-cookie:" line as
+ received from a server.
+
+ The function need to replace previously stored lines that this new
+ line superceeds.
+
+ It may remove lines that are expired.
+
+ It should return an indication of success/error.
+
+
+SENDING COOKIE INFORMATION
+==========================
+
+struct Cookies *cookie_getlist(struct CookieInfo *cookie,
+ char *host, char *path, bool secure);
+
+ For a given host and path, return a linked list of cookies that
+ the client should send to the server if used now. The secure
+ boolean informs the cookie if a secure connection is achieved or
+ not.
+
+ It shall only return cookies that haven't expired.
+
+
+Example set of cookies:
+
+ Set-cookie: PRODUCTINFO=webxpress; domain=.fidelity.com; path=/; secure
+ Set-cookie: PERSONALIZE=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/ftgw; secure
+ Set-cookie: FidHist=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: FidOrder=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: DisPend=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie: FidDis=none;expires=Monday, 13-Jun-1988 03:04:55 GMT;
+ domain=.fidelity.com; path=/; secure
+ Set-cookie:
+ Session_Key@6791a9e0-901a-11d0-a1c8-9b012c88aa77=none;expires=Monday,
+ 13-Jun-1988 03:04:55 GMT; domain=.fidelity.com; path=/; secure
+****/
+
+
+#include "curl_setup.h"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+
+#define _MPRINTF_REPLACE
+#include <curl/mprintf.h>
+
+#include "urldata.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "sendf.h"
+#include "slist.h"
+#include "curl_memory.h"
+#include "share.h"
+#include "strtoofft.h"
+#include "rawstr.h"
+#include "curl_memrchr.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static void freecookie(struct Cookie *co)
+{
+ if(co->expirestr)
+ free(co->expirestr);
+ if(co->domain)
+ free(co->domain);
+ if(co->path)
+ free(co->path);
+ if(co->spath)
+ free(co->spath);
+ if(co->name)
+ free(co->name);
+ if(co->value)
+ free(co->value);
+ if(co->maxage)
+ free(co->maxage);
+ if(co->version)
+ free(co->version);
+
+ free(co);
+}
+
+static bool tailmatch(const char *cooke_domain, const char *hostname)
+{
+ size_t cookie_domain_len = strlen(cooke_domain);
+ size_t hostname_len = strlen(hostname);
+
+ if(hostname_len < cookie_domain_len)
+ return FALSE;
+
+ if(!Curl_raw_equal(cooke_domain, hostname+hostname_len-cookie_domain_len))
+ return FALSE;
+
+ /* A lead char of cookie_domain is not '.'.
+ RFC6265 4.1.2.3. The Domain Attribute says:
+ For example, if the value of the Domain attribute is
+ "example.com", the user agent will include the cookie in the Cookie
+ header when making HTTP requests to example.com, www.example.com, and
+ www.corp.example.com.
+ */
+ if(hostname_len == cookie_domain_len)
+ return TRUE;
+ if('.' == *(hostname + hostname_len - cookie_domain_len - 1))
+ return TRUE;
+ 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).
+ */
+void Curl_cookie_loadfiles(struct SessionHandle *data)
+{
+ struct curl_slist *list = data->change.cookielist;
+ if(list) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ while(list) {
+ data->cookies = Curl_cookie_init(data,
+ list->data,
+ data->cookies,
+ data->set.cookiesession);
+ list = list->next;
+ }
+ curl_slist_free_all(data->change.cookielist); /* clean up list */
+ data->change.cookielist = NULL; /* don't do this again! */
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+}
+
+/*
+ * strstore() makes a strdup() on the 'newstr' and if '*str' is non-NULL
+ * that will be freed before the allocated string is stored there.
+ *
+ * It is meant to easily replace strdup()
+ */
+static void strstore(char **str, const char *newstr)
+{
+ if(*str)
+ free(*str);
+ *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;
+ }
+}
+
+/****************************************************************************
+ *
+ * Curl_cookie_add()
+ *
+ * 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 *
+Curl_cookie_add(struct SessionHandle *data,
+ /* The 'data' pointer here may be NULL at times, and thus
+ must only be used very carefully for things that can deal
+ with data being NULL. Such as infof() and similar */
+
+ struct CookieInfo *c,
+ bool httpheader, /* TRUE if HTTP header-style line */
+ char *lineptr, /* first character of the line */
+ const char *domain, /* default domain */
+ const char *path) /* full path used when this cookie is set,
+ used to get default path for the cookie
+ unless set */
+{
+ struct Cookie *clist;
+ char name[MAX_NAME];
+ struct Cookie *co;
+ struct Cookie *lastc=NULL;
+ time_t now = time(NULL);
+ bool replace_old = FALSE;
+ bool badcookie = FALSE; /* cookies are good by default. mmmmm yummy */
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)data;
+#endif
+
+ /* First, alloc and init a new struct for it */
+ co = calloc(1, sizeof(struct Cookie));
+ if(!co)
+ return NULL; /* bail out if we're this low on memory */
+
+ if(httpheader) {
+ /* This line was read off a HTTP-header */
+ const char *ptr;
+ const char *semiptr;
+ char *what;
+
+ what = malloc(MAX_COOKIE_LINE);
+ if(!what) {
+ free(co);
+ return NULL;
+ }
+
+ semiptr=strchr(lineptr, ';'); /* first, find a semicolon */
+
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+
+ ptr = lineptr;
+ do {
+ /* we have a <what>=<this> pair or a stand-alone word here */
+ name[0]=what[0]=0; /* init the buffers */
+ if(1 <= sscanf(ptr, "%" MAX_NAME_TXT "[^;\r\n =]=%"
+ MAX_COOKIE_LINE_TXT "[^;\r\n]",
+ name, what)) {
+ /* Use strstore() below to properly deal with received cookie
+ headers that have the same string property set more than once,
+ and then we use the last one. */
+ const char *whatptr;
+ bool done = FALSE;
+ bool sep;
+ size_t len=strlen(what);
+ const char *endofn = &ptr[ strlen(name) ];
+
+ /* skip trailing spaces in name */
+ while(*endofn && ISBLANK(*endofn))
+ endofn++;
+
+ /* name ends with a '=' ? */
+ sep = (*endofn == '=')?TRUE:FALSE;
+
+ /* Strip off trailing whitespace from the 'what' */
+ while(len && ISBLANK(what[len-1])) {
+ what[len-1]=0;
+ len--;
+ }
+
+ /* Skip leading whitespace from the 'what' */
+ whatptr=what;
+ while(*whatptr && ISBLANK(*whatptr))
+ whatptr++;
+
+ if(!len) {
+ /* this was a "<name>=" with no content, and we must allow
+ 'secure' and 'httponly' specified this weirdly */
+ done = TRUE;
+ if(Curl_raw_equal("secure", name))
+ co->secure = TRUE;
+ else if(Curl_raw_equal("httponly", name))
+ co->httponly = TRUE;
+ else if(sep)
+ /* there was a '=' so we're not done parsing this field */
+ done = FALSE;
+ }
+ if(done)
+ ;
+ else if(Curl_raw_equal("path", name)) {
+ strstore(&co->path, whatptr);
+ if(!co->path) {
+ 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)) {
+ /* Now, we make sure that our host is within the given domain,
+ or the given domain is not valid and thus cannot be set. */
+
+ if('.' == whatptr[0])
+ whatptr++; /* ignore preceding dot */
+
+ if(!domain || tailmatch(whatptr, domain)) {
+ const char *tailptr=whatptr;
+ if(tailptr[0] == '.')
+ tailptr++;
+ strstore(&co->domain, tailptr); /* don't prefix w/dots
+ internally */
+ if(!co->domain) {
+ badcookie = TRUE;
+ break;
+ }
+ co->tailmatch=TRUE; /* we always do that if the domain name was
+ given */
+ }
+ else {
+ /* we did not get a tailmatch and then the attempted set domain
+ is not a domain to which the current host belongs. Mark as
+ bad. */
+ badcookie=TRUE;
+ infof(data, "skipped cookie with bad tailmatch domain: %s\n",
+ whatptr);
+ }
+ }
+ else if(Curl_raw_equal("version", name)) {
+ strstore(&co->version, whatptr);
+ if(!co->version) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ else if(Curl_raw_equal("max-age", name)) {
+ /* Defined in RFC2109:
+
+ Optional. The Max-Age attribute defines the lifetime of the
+ cookie, in seconds. The delta-seconds value is a decimal non-
+ negative integer. After delta-seconds seconds elapse, the
+ client should discard the cookie. A value of zero means the
+ cookie should be discarded immediately.
+
+ */
+ strstore(&co->maxage, whatptr);
+ if(!co->maxage) {
+ badcookie = TRUE;
+ break;
+ }
+ co->expires =
+ strtol((*co->maxage=='\"')?&co->maxage[1]:&co->maxage[0],NULL,10)
+ + (long)now;
+ }
+ else if(Curl_raw_equal("expires", name)) {
+ strstore(&co->expirestr, whatptr);
+ if(!co->expirestr) {
+ badcookie = TRUE;
+ break;
+ }
+ /* Note that if the date couldn't get parsed for whatever reason,
+ the cookie will be treated as a session cookie */
+ co->expires = curl_getdate(what, &now);
+
+ /* Session cookies have expires set to 0 so if we get that back
+ from the date parser let's add a second to make it a
+ non-session cookie */
+ if(co->expires == 0)
+ co->expires = 1;
+ else if(co->expires < 0)
+ co->expires = 0;
+ }
+ else if(!co->name) {
+ co->name = strdup(name);
+ co->value = strdup(whatptr);
+ if(!co->name || !co->value) {
+ badcookie = TRUE;
+ break;
+ }
+ }
+ /*
+ else this is the second (or more) name we don't know
+ about! */
+ }
+ else {
+ /* this is an "illegal" <what>=<this> pair */
+ }
+
+ if(!semiptr || !*semiptr) {
+ /* we already know there are no more cookies */
+ semiptr = NULL;
+ continue;
+ }
+
+ ptr=semiptr+1;
+ while(*ptr && ISBLANK(*ptr))
+ ptr++;
+ semiptr=strchr(ptr, ';'); /* now, find the next semicolon */
+
+ if(!semiptr && *ptr)
+ /* There are no more semicolons, but there's a final name=value pair
+ coming up */
+ semiptr=strchr(ptr, '\0');
+ } while(semiptr);
+
+ if(!badcookie && !co->domain) {
+ if(domain) {
+ /* no domain was given in the header line, set the default */
+ co->domain=strdup(domain);
+ if(!co->domain)
+ badcookie = TRUE;
+ }
+ }
+
+ if(!badcookie && !co->path && path) {
+ /* No path was given in the header line, set the default.
+ Note that the passed-in path to this function MAY have a '?' and
+ following part that MUST not be stored as part of the path. */
+ char *queryp = strchr(path, '?');
+
+ /* queryp is where the interesting part of the path ends, so now we
+ want to the find the last */
+ char *endslash;
+ if(!queryp)
+ endslash = strrchr(path, '/');
+ else
+ endslash = memrchr(path, '/', (size_t)(queryp - path));
+ if(endslash) {
+ size_t pathlen = (size_t)(endslash-path+1); /* include ending slash */
+ co->path=malloc(pathlen+1); /* one extra for the zero byte */
+ 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;
+ }
+ }
+
+ free(what);
+
+ if(badcookie || !co->name) {
+ /* we didn't get a cookie name or a bad one,
+ this is an illegal line, bail out */
+ freecookie(co);
+ return NULL;
+ }
+
+ }
+ else {
+ /* This line is NOT a HTTP header style line, we do offer support for
+ reading the odd netscape cookies-file format here */
+ char *ptr;
+ char *firstptr;
+ char *tok_buf=NULL;
+ int fields;
+
+ /* IE introduced HTTP-only cookies to prevent XSS attacks. Cookies
+ marked with httpOnly after the domain name are not accessible
+ from javascripts, but since curl does not operate at javascript
+ level, we include them anyway. In Firefox's cookie files, these
+ lines are preceded with #HttpOnly_ and then everything is
+ as usual, so we skip 10 characters of the line..
+ */
+ if(strncmp(lineptr, "#HttpOnly_", 10) == 0) {
+ lineptr += 10;
+ co->httponly = TRUE;
+ }
+
+ if(lineptr[0]=='#') {
+ /* don't even try the comments */
+ free(co);
+ return NULL;
+ }
+ /* strip off the possible end-of-line characters */
+ ptr=strchr(lineptr, '\r');
+ if(ptr)
+ *ptr=0; /* clear it */
+ ptr=strchr(lineptr, '\n');
+ if(ptr)
+ *ptr=0; /* clear it */
+
+ firstptr=strtok_r(lineptr, "\t", &tok_buf); /* tokenize it on the TAB */
+
+ /* Now loop through the fields and init the struct we already have
+ allocated */
+ for(ptr=firstptr, fields=0; ptr && !badcookie;
+ ptr=strtok_r(NULL, "\t", &tok_buf), fields++) {
+ switch(fields) {
+ case 0:
+ if(ptr[0]=='.') /* skip preceding dots */
+ ptr++;
+ co->domain = strdup(ptr);
+ if(!co->domain)
+ badcookie = TRUE;
+ break;
+ case 1:
+ /* This field got its explanation on the 23rd of May 2001 by
+ Andrs Garca:
+
+ flag: A TRUE/FALSE value indicating if all machines within a given
+ domain can access the variable. This value is set automatically by
+ the browser, depending on the value you set for the domain.
+
+ As far as I can see, it is set to true when the cookie says
+ .domain.com and to false when the domain is complete www.domain.com
+ */
+ co->tailmatch = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
+ break;
+ case 2:
+ /* It turns out, that sometimes the file format allows the path
+ field to remain not filled in, we try to detect this and work
+ around it! Andrs Garca made us aware of this... */
+ if(strcmp("TRUE", ptr) && strcmp("FALSE", ptr)) {
+ /* only if the path doesn't look like a boolean option! */
+ 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:
+ co->secure = Curl_raw_equal(ptr, "TRUE")?TRUE:FALSE;
+ break;
+ case 4:
+ co->expires = curlx_strtoofft(ptr, NULL, 10);
+ break;
+ case 5:
+ co->name = strdup(ptr);
+ if(!co->name)
+ badcookie = TRUE;
+ break;
+ case 6:
+ co->value = strdup(ptr);
+ if(!co->value)
+ badcookie = TRUE;
+ break;
+ }
+ }
+ if(6 == fields) {
+ /* we got a cookie with blank contents, fix it */
+ co->value = strdup("");
+ if(!co->value)
+ badcookie = TRUE;
+ else
+ fields++;
+ }
+
+ if(!badcookie && (7 != fields))
+ /* we did not find the sufficient number of fields */
+ badcookie = TRUE;
+
+ if(badcookie) {
+ freecookie(co);
+ return NULL;
+ }
+
+ }
+
+ if(!c->running && /* read from a file */
+ c->newsession && /* clean session cookies */
+ !co->expires) { /* this is a session cookie since it doesn't expire! */
+ freecookie(co);
+ return NULL;
+ }
+
+ co->livecookie = c->running;
+
+ /* now, we have parsed the incoming line, we must now check if this
+ 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) {
+ if(Curl_raw_equal(clist->name, co->name)) {
+ /* the names are identical */
+
+ if(clist->domain && co->domain) {
+ if(Curl_raw_equal(clist->domain, co->domain))
+ /* The domains are identical */
+ replace_old=TRUE;
+ }
+ else if(!clist->domain && !co->domain)
+ replace_old = TRUE;
+
+ if(replace_old) {
+ /* the domains were identical */
+
+ if(clist->spath && co->spath) {
+ if(Curl_raw_equal(clist->spath, co->spath)) {
+ replace_old = TRUE;
+ }
+ else
+ replace_old = FALSE;
+ }
+ else if(!clist->spath && !co->spath)
+ replace_old = TRUE;
+ else
+ replace_old = FALSE;
+
+ }
+
+ if(replace_old && !co->livecookie && clist->livecookie) {
+ /* Both cookies matched fine, except that the already present
+ cookie is "live", which means it was set from a header, while
+ the new one isn't "live" and thus only read from a file. We let
+ live cookies stay alive */
+
+ /* Free the newcomer and get out of here! */
+ freecookie(co);
+ return NULL;
+ }
+
+ if(replace_old) {
+ co->next = clist->next; /* get the next-pointer first */
+
+ /* then free all the old pointers */
+ free(clist->name);
+ if(clist->value)
+ free(clist->value);
+ if(clist->domain)
+ free(clist->domain);
+ if(clist->path)
+ free(clist->path);
+ if(clist->spath)
+ free(clist->spath);
+ if(clist->expirestr)
+ free(clist->expirestr);
+
+ if(clist->version)
+ free(clist->version);
+ if(clist->maxage)
+ free(clist->maxage);
+
+ *clist = *co; /* then store all the new data */
+
+ free(co); /* free the newly alloced memory */
+ co = clist; /* point to the previous struct instead */
+
+ /* We have replaced a cookie, now skip the rest of the list but
+ make sure the 'lastc' pointer is properly set */
+ do {
+ lastc = clist;
+ clist = clist->next;
+ } while(clist);
+ break;
+ }
+ }
+ lastc = clist;
+ clist = clist->next;
+ }
+
+ if(c->running)
+ /* Only show this when NOT reading the cookies from a file */
+ infof(data, "%s cookie %s=\"%s\" for domain %s, path %s, "
+ "expire %" FORMAT_OFF_T "\n",
+ replace_old?"Replaced":"Added", co->name, co->value,
+ co->domain, co->path, co->expires);
+
+ if(!replace_old) {
+ /* then make the last item point on this new one */
+ if(lastc)
+ lastc->next = co;
+ else
+ c->cookies = co;
+ c->numcookies++; /* one more cookie in the jar */
+ }
+
+ return co;
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_init()
+ *
+ * Inits a cookie struct to read data from a local file. This is always
+ * called before any cookies are set. File may be NULL.
+ *
+ * If 'newsession' is TRUE, discard all "session cookies" on read from file.
+ *
+ ****************************************************************************/
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+ const char *file,
+ struct CookieInfo *inc,
+ bool newsession)
+{
+ struct CookieInfo *c;
+ FILE *fp;
+ bool fromfile=TRUE;
+
+ if(NULL == inc) {
+ /* we didn't get a struct, create one */
+ c = calloc(1, sizeof(struct CookieInfo));
+ if(!c)
+ return NULL; /* failed to get memory */
+ c->filename = strdup(file?file:"none"); /* copy the name just in case */
+ }
+ else {
+ /* we got an already existing one, use that */
+ c = inc;
+ }
+ c->running = FALSE; /* this is not running, this is init */
+
+ if(file && strequal(file, "-")) {
+ fp = stdin;
+ fromfile=FALSE;
+ }
+ else if(file && !*file) {
+ /* points to a "" string */
+ fp = NULL;
+ }
+ else
+ fp = file?fopen(file, "r"):NULL;
+
+ c->newsession = newsession; /* new session? */
+
+ if(fp) {
+ char *lineptr;
+ bool headerline;
+
+ char *line = malloc(MAX_COOKIE_LINE);
+ if(line) {
+ while(fgets(line, MAX_COOKIE_LINE, fp)) {
+ if(checkprefix("Set-Cookie:", line)) {
+ /* This is a cookie line, get it! */
+ lineptr=&line[11];
+ headerline=TRUE;
+ }
+ else {
+ lineptr=line;
+ headerline=FALSE;
+ }
+ while(*lineptr && ISBLANK(*lineptr))
+ lineptr++;
+
+ Curl_cookie_add(data, c, headerline, lineptr, NULL, NULL);
+ }
+ free(line); /* free the line buffer */
+ }
+ if(fromfile)
+ fclose(fp);
+ }
+
+ c->running = TRUE; /* now, we're running */
+
+ return c;
+}
+
+/* sort this so that the longest path gets before the shorter path */
+static int cookie_sort(const void *p1, const void *p2)
+{
+ struct Cookie *c1 = *(struct Cookie **)p1;
+ struct Cookie *c2 = *(struct Cookie **)p2;
+ size_t l1, l2;
+
+ /* 1 - compare cookie path lengths */
+ l1 = c1->path ? strlen(c1->path) : 0;
+ l2 = c2->path ? strlen(c2->path) : 0;
+
+ if(l1 != l2)
+ return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+
+ /* 2 - compare cookie domain lengths */
+ l1 = c1->domain ? strlen(c1->domain) : 0;
+ l2 = c2->domain ? strlen(c2->domain) : 0;
+
+ if(l1 != l2)
+ return (l2 > l1) ? 1 : -1 ; /* avoid size_t <=> int conversions */
+
+ /* 3 - compare cookie names */
+ if(c1->name && c2->name)
+ return strcmp(c1->name, c2->name);
+
+ /* sorry, can't be more deterministic */
+ return 0;
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_getlist()
+ *
+ * For a given host and path, return a linked list of cookies that the
+ * client should send to the server if used now. The secure boolean informs
+ * the cookie if a secure connection is achieved or not.
+ *
+ * It shall only return cookies that haven't expired.
+ *
+ ****************************************************************************/
+
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *c,
+ const char *host, const char *path,
+ bool secure)
+{
+ struct Cookie *newco;
+ struct Cookie *co;
+ time_t now = time(NULL);
+ struct Cookie *mainco=NULL;
+ size_t matches = 0;
+
+ 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) {
+ /* only process this cookie if it is not expired or had no expire
+ date AND that if the cookie requires we're secure we must only
+ continue if we are! */
+ if((!co->expires || (co->expires > now)) &&
+ (co->secure?secure:TRUE)) {
+
+ /* now check if the domain is correct */
+ if(!co->domain ||
+ (co->tailmatch && tailmatch(co->domain, host)) ||
+ (!co->tailmatch && Curl_raw_equal(host, co->domain)) ) {
+ /* the right part of the host matches the domain stuff in the
+ cookie data */
+
+ /* now check the left part of the path with the cookies path
+ requirement */
+ 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 */
+
+ newco = malloc(sizeof(struct Cookie));
+ if(newco) {
+ /* first, copy the whole source cookie: */
+ memcpy(newco, co, sizeof(struct Cookie));
+
+ /* then modify our next */
+ newco->next = mainco;
+
+ /* point the main to us */
+ mainco = newco;
+
+ matches++;
+ }
+ else {
+ fail:
+ /* failure, clear up the allocated chain and return NULL */
+ while(mainco) {
+ co = mainco->next;
+ free(mainco);
+ mainco = co;
+ }
+
+ return NULL;
+ }
+ }
+ }
+ }
+ co = co->next;
+ }
+
+ if(matches) {
+ /* Now we need to make sure that if there is a name appearing more than
+ once, the longest specified path version comes first. To make this
+ the swiftest way, we just sort them all based on path length. */
+ struct Cookie **array;
+ size_t i;
+
+ /* alloc an array and store all cookie pointers */
+ array = malloc(sizeof(struct Cookie *) * matches);
+ if(!array)
+ goto fail;
+
+ co = mainco;
+
+ for(i=0; co; co = co->next)
+ array[i++] = co;
+
+ /* now sort the cookie pointers in path length order */
+ qsort(array, matches, sizeof(struct Cookie *), cookie_sort);
+
+ /* remake the linked list order according to the new order */
+
+ mainco = array[0]; /* start here */
+ for(i=0; i<matches-1; i++)
+ array[i]->next = array[i+1];
+ array[matches-1]->next = NULL; /* terminate the list */
+
+ free(array); /* remove the temporary data again */
+ }
+
+ return mainco; /* return the new list */
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearall()
+ *
+ * Clear all existing cookies and reset the counter.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearall(struct CookieInfo *cookies)
+{
+ if(cookies) {
+ Curl_cookie_freelist(cookies->cookies, TRUE);
+ cookies->cookies = NULL;
+ cookies->numcookies = 0;
+ }
+}
+
+/*****************************************************************************
+ *
+ * Curl_cookie_freelist()
+ *
+ * Free a list of cookies previously returned by Curl_cookie_getlist();
+ *
+ * The 'cookiestoo' argument tells this function whether to just free the
+ * list or actually also free all cookies within the list as well.
+ *
+ ****************************************************************************/
+
+void Curl_cookie_freelist(struct Cookie *co, bool cookiestoo)
+{
+ struct Cookie *next;
+ if(co) {
+ while(co) {
+ next = co->next;
+ if(cookiestoo)
+ freecookie(co);
+ else
+ free(co); /* we only free the struct since the "members" are all just
+ pointed out in the main cookie list! */
+ co = next;
+ }
+ }
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_clearsess()
+ *
+ * Free all session cookies in the cookies list.
+ *
+ ****************************************************************************/
+void Curl_cookie_clearsess(struct CookieInfo *cookies)
+{
+ struct Cookie *first, *curr, *next, *prev = NULL;
+
+ if(!cookies || !cookies->cookies)
+ return;
+
+ first = curr = prev = cookies->cookies;
+
+ for(; curr; curr = next) {
+ next = curr->next;
+ if(!curr->expires) {
+ if(first == curr)
+ first = next;
+
+ if(prev == curr)
+ prev = next;
+ else
+ prev->next = next;
+
+ freecookie(curr);
+ cookies->numcookies--;
+ }
+ else
+ prev = curr;
+ }
+
+ cookies->cookies = first;
+}
+
+
+/*****************************************************************************
+ *
+ * Curl_cookie_cleanup()
+ *
+ * Free a "cookie object" previous created with cookie_init().
+ *
+ ****************************************************************************/
+void Curl_cookie_cleanup(struct CookieInfo *c)
+{
+ struct Cookie *co;
+ struct Cookie *next;
+ if(c) {
+ if(c->filename)
+ free(c->filename);
+ co = c->cookies;
+
+ while(co) {
+ next = co->next;
+ freecookie(co);
+ co = next;
+ }
+ free(c); /* free the base struct as well */
+ }
+}
+
+/* get_netscape_format()
+ *
+ * Formats a string for Netscape output file, w/o a newline at the end.
+ *
+ * Function returns a char * to a formatted line. Has to be free()d
+*/
+static char *get_netscape_format(const struct Cookie *co)
+{
+ return aprintf(
+ "%s" /* httponly preamble */
+ "%s%s\t" /* domain */
+ "%s\t" /* tailmatch */
+ "%s\t" /* path */
+ "%s\t" /* secure */
+ "%" FORMAT_OFF_T "\t" /* expires */
+ "%s\t" /* name */
+ "%s", /* value */
+ co->httponly?"#HttpOnly_":"",
+ /* Make sure all domains are prefixed with a dot if they allow
+ tailmatching. This is Mozilla-style. */
+ (co->tailmatch && co->domain && co->domain[0] != '.')? ".":"",
+ co->domain?co->domain:"unknown",
+ co->tailmatch?"TRUE":"FALSE",
+ co->path?co->path:"/",
+ co->secure?"TRUE":"FALSE",
+ co->expires,
+ co->name,
+ co->value?co->value:"");
+}
+
+/*
+ * cookie_output()
+ *
+ * Writes all internally known cookies to the specified file. Specify
+ * "-" as file name to write to stdout.
+ *
+ * The function returns non-zero on write failure.
+ */
+static int cookie_output(struct CookieInfo *c, const char *dumphere)
+{
+ struct Cookie *co;
+ FILE *out;
+ bool use_stdout=FALSE;
+
+ if((NULL == c) || (0 == c->numcookies))
+ /* If there are no known cookies, we don't write or even create any
+ destination file */
+ return 0;
+
+ /* at first, remove expired cookies */
+ remove_expired(c);
+
+ if(strequal("-", dumphere)) {
+ /* use stdout */
+ out = stdout;
+ use_stdout=TRUE;
+ }
+ else {
+ out = fopen(dumphere, "w");
+ if(!out)
+ return 1; /* failure */
+ }
+
+ if(c) {
+ char *format_ptr;
+
+ fputs("# Netscape HTTP Cookie File\n"
+ "# http://curl.haxx.se/docs/http-cookies.html\n"
+ "# This file was generated by libcurl! Edit at your own risk.\n\n",
+ out);
+ co = c->cookies;
+
+ while(co) {
+ format_ptr = get_netscape_format(co);
+ if(format_ptr == NULL) {
+ fprintf(out, "#\n# Fatal libcurl error\n");
+ if(!use_stdout)
+ fclose(out);
+ return 1;
+ }
+ fprintf(out, "%s\n", format_ptr);
+ free(format_ptr);
+ co=co->next;
+ }
+ }
+
+ if(!use_stdout)
+ fclose(out);
+
+ return 0;
+}
+
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data)
+{
+ struct curl_slist *list = NULL;
+ struct curl_slist *beg;
+ struct Cookie *c;
+ char *line;
+
+ if((data->cookies == NULL) ||
+ (data->cookies->numcookies == 0))
+ return NULL;
+
+ c = data->cookies->cookies;
+
+ while(c) {
+ /* fill the list with _all_ the cookies we know */
+ line = get_netscape_format(c);
+ if(!line) {
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ beg = Curl_slist_append_nodup(list, line);
+ if(!beg) {
+ free(line);
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ list = beg;
+ c = c->next;
+ }
+
+ return list;
+}
+
+void Curl_flush_cookies(struct SessionHandle *data, int cleanup)
+{
+ if(data->set.str[STRING_COOKIEJAR]) {
+ if(data->change.cookielist) {
+ /* If there is a list of cookie files to read, do it first so that
+ we have all the told files read before we write the new jar.
+ Curl_cookie_loadfiles() LOCKS and UNLOCKS the share itself! */
+ Curl_cookie_loadfiles(data);
+ }
+
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+ /* if we have a destination file for all the cookies to get dumped to */
+ if(cookie_output(data->cookies, data->set.str[STRING_COOKIEJAR]))
+ infof(data, "WARNING: failed to save cookies in %s\n",
+ data->set.str[STRING_COOKIEJAR]);
+ }
+ else {
+ if(cleanup && data->change.cookielist) {
+ /* since nothing is written, we can just free the list of cookie file
+ names */
+ curl_slist_free_all(data->change.cookielist); /* clean up list */
+ data->change.cookielist = NULL;
+ }
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ }
+
+ if(cleanup && (!data->share || (data->cookies != data->share->cookies))) {
+ Curl_cookie_cleanup(data->cookies);
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+}
+
+#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_COOKIES */
diff --git a/libs/libcurl/src/cookie.h b/libs/libcurl/src/cookie.h
new file mode 100644
index 0000000000..bd890827c7
--- /dev/null
+++ b/libs/libcurl/src/cookie.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_COOKIE_H
+#define HEADER_CURL_COOKIE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 <curl/curl.h>
+
+struct Cookie {
+ struct Cookie *next; /* next in the chain */
+ char *name; /* <this> = value */
+ char *value; /* name = <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 */
+ bool tailmatch; /* weather we do tail-matchning of the domain name */
+
+ /* RFC 2109 keywords. Version=1 means 2109-compliant cookie sending */
+ char *version; /* Version = <value> */
+ char *maxage; /* Max-Age = <value> */
+
+ bool secure; /* whether the 'secure' keyword was used */
+ bool livecookie; /* updated from a server, not a stored file */
+ bool httponly; /* true if the httponly directive is present */
+};
+
+struct CookieInfo {
+ /* linked list of cookies we know of */
+ struct Cookie *cookies;
+
+ char *filename; /* file we read from/write to */
+ bool running; /* state info, for cookie adding information */
+ long numcookies; /* number of cookies in the "jar" */
+ bool newsession; /* new session, discard session cookies on load */
+};
+
+/* This is the maximum line length we accept for a cookie line. RFC 2109
+ section 6.3 says:
+
+ "at least 4096 bytes per cookie (as measured by the size of the characters
+ that comprise the cookie non-terminal in the syntax description of the
+ Set-Cookie header)"
+
+*/
+#define MAX_COOKIE_LINE 5000
+#define MAX_COOKIE_LINE_TXT "4999"
+
+/* This is the maximum length of a cookie name we deal with: */
+#define MAX_NAME 1024
+#define MAX_NAME_TXT "1023"
+
+struct SessionHandle;
+/*
+ * Add a cookie to the internal list of cookies. The domain and path arguments
+ * are only used if the header boolean is TRUE.
+ */
+
+struct Cookie *Curl_cookie_add(struct SessionHandle *data,
+ struct CookieInfo *, bool header, char *lineptr,
+ const char *domain, const char *path);
+
+struct Cookie *Curl_cookie_getlist(struct CookieInfo *, const char *,
+ const char *, bool);
+void Curl_cookie_freelist(struct Cookie *cookies, bool cookiestoo);
+void Curl_cookie_clearall(struct CookieInfo *cookies);
+void Curl_cookie_clearsess(struct CookieInfo *cookies);
+
+#if defined(CURL_DISABLE_HTTP) || defined(CURL_DISABLE_COOKIES)
+#define Curl_cookie_list(x) NULL
+#define Curl_cookie_loadfiles(x) Curl_nop_stmt
+#define Curl_cookie_init(x,y,z,w) NULL
+#define Curl_cookie_cleanup(x) Curl_nop_stmt
+#define Curl_flush_cookies(x,y) Curl_nop_stmt
+#else
+void Curl_flush_cookies(struct SessionHandle *data, int cleanup);
+void Curl_cookie_cleanup(struct CookieInfo *);
+struct CookieInfo *Curl_cookie_init(struct SessionHandle *data,
+ const char *, struct CookieInfo *, bool);
+struct curl_slist *Curl_cookie_list(struct SessionHandle *data);
+void Curl_cookie_loadfiles(struct SessionHandle *data);
+#endif
+
+#endif /* HEADER_CURL_COOKIE_H */
diff --git a/libs/libcurl/src/curl_addrinfo.c b/libs/libcurl/src/curl_addrinfo.c
new file mode 100644
index 0000000000..10652c642c
--- /dev/null
+++ b/libs/libcurl/src/curl_addrinfo.c
@@ -0,0 +1,527 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 <curl/curl.h>
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+# include <in.h>
+# include <inet.h>
+#endif
+
+#if defined(NETWARE) && defined(__NOVELL_LIBC__)
+# undef in_addr_t
+# define in_addr_t unsigned long
+#endif
+
+#include "curl_addrinfo.h"
+#include "inet_pton.h"
+#include "warnless.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"
+
+
+/*
+ * Curl_freeaddrinfo()
+ *
+ * This is used to free a linked list of Curl_addrinfo structs along
+ * with all its associated allocated storage. This function should be
+ * called once for each successful call to Curl_getaddrinfo_ex() or to
+ * any function call which actually allocates a Curl_addrinfo struct.
+ */
+
+#if defined(__INTEL_COMPILER) && (__INTEL_COMPILER == 910) && \
+ defined(__OPTIMIZE__) && defined(__unix__) && defined(__i386__)
+ /* workaround icc 9.1 optimizer issue */
+# define vqualifier volatile
+#else
+# define vqualifier
+#endif
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead)
+{
+ Curl_addrinfo *vqualifier canext;
+ Curl_addrinfo *ca;
+
+ for(ca = cahead; ca != NULL; ca = canext) {
+
+ if(ca->ai_addr)
+ free(ca->ai_addr);
+
+ if(ca->ai_canonname)
+ free(ca->ai_canonname);
+
+ canext = ca->ai_next;
+
+ free(ca);
+ }
+}
+
+
+#ifdef HAVE_GETADDRINFO
+/*
+ * Curl_getaddrinfo_ex()
+ *
+ * This is a wrapper function around system's getaddrinfo(), with
+ * the only difference that instead of returning a linked list of
+ * addrinfo structs this one returns a linked list of Curl_addrinfo
+ * ones. The memory allocated by this function *MUST* be free'd with
+ * Curl_freeaddrinfo(). For each successful call to this function
+ * there must be an associated call later to Curl_freeaddrinfo().
+ *
+ * There should be no single call to system's getaddrinfo() in the
+ * whole library, any such call should be 'routed' through this one.
+ */
+
+int
+Curl_getaddrinfo_ex(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ Curl_addrinfo **result)
+{
+ const struct addrinfo *ai;
+ struct addrinfo *aihead;
+ Curl_addrinfo *cafirst = NULL;
+ Curl_addrinfo *calast = NULL;
+ Curl_addrinfo *ca;
+ size_t ss_size;
+ int error;
+
+ *result = NULL; /* assume failure */
+
+ error = getaddrinfo(nodename, servname, hints, &aihead);
+ if(error)
+ return error;
+
+ /* traverse the addrinfo list */
+
+ for(ai = aihead; ai != NULL; ai = ai->ai_next) {
+
+ /* ignore elements with unsupported address family, */
+ /* settle family-specific sockaddr structure size. */
+ if(ai->ai_family == AF_INET)
+ ss_size = sizeof(struct sockaddr_in);
+#ifdef ENABLE_IPV6
+ else if(ai->ai_family == AF_INET6)
+ ss_size = sizeof(struct sockaddr_in6);
+#endif
+ else
+ continue;
+
+ /* ignore elements without required address info */
+ if((ai->ai_addr == NULL) || !(ai->ai_addrlen > 0))
+ continue;
+
+ /* ignore elements with bogus address size */
+ if((size_t)ai->ai_addrlen < ss_size)
+ continue;
+
+ if((ca = malloc(sizeof(Curl_addrinfo))) == NULL) {
+ error = EAI_MEMORY;
+ break;
+ }
+
+ /* copy each structure member individually, member ordering, */
+ /* size, or padding might be different for each platform. */
+
+ ca->ai_flags = ai->ai_flags;
+ ca->ai_family = ai->ai_family;
+ ca->ai_socktype = ai->ai_socktype;
+ ca->ai_protocol = ai->ai_protocol;
+ ca->ai_addrlen = (curl_socklen_t)ss_size;
+ ca->ai_addr = NULL;
+ ca->ai_canonname = NULL;
+ ca->ai_next = NULL;
+
+ if((ca->ai_addr = malloc(ss_size)) == NULL) {
+ error = EAI_MEMORY;
+ free(ca);
+ break;
+ }
+ memcpy(ca->ai_addr, ai->ai_addr, ss_size);
+
+ if(ai->ai_canonname != NULL) {
+ if((ca->ai_canonname = strdup(ai->ai_canonname)) == NULL) {
+ error = EAI_MEMORY;
+ free(ca->ai_addr);
+ free(ca);
+ break;
+ }
+ }
+
+ /* if the return list is empty, this becomes the first element */
+ if(!cafirst)
+ cafirst = ca;
+
+ /* add this element last in the return list */
+ if(calast)
+ calast->ai_next = ca;
+ calast = ca;
+
+ }
+
+ /* destroy the addrinfo list */
+ if(aihead)
+ freeaddrinfo(aihead);
+
+ /* if we failed, also destroy the Curl_addrinfo list */
+ if(error) {
+ Curl_freeaddrinfo(cafirst);
+ cafirst = NULL;
+ }
+ else if(!cafirst) {
+#ifdef EAI_NONAME
+ /* rfc3493 conformant */
+ error = EAI_NONAME;
+#else
+ /* rfc3493 obsoleted */
+ error = EAI_NODATA;
+#endif
+#ifdef USE_WINSOCK
+ SET_SOCKERRNO(error);
+#endif
+ }
+
+ *result = cafirst;
+
+ /* This is not a CURLcode */
+ return error;
+}
+#endif /* HAVE_GETADDRINFO */
+
+
+/*
+ * Curl_he2ai()
+ *
+ * This function returns a pointer to the first element of a newly allocated
+ * Curl_addrinfo struct linked list filled with the data of a given hostent.
+ * Curl_addrinfo is meant to work like the addrinfo struct does for a IPv6
+ * stack, but usable also for IPv4, all hosts and environments.
+ *
+ * The memory allocated by this function *MUST* be free'd later on calling
+ * Curl_freeaddrinfo(). For each successful call to this function there
+ * must be an associated call later to Curl_freeaddrinfo().
+ *
+ * Curl_addrinfo defined in "lib/curl_addrinfo.h"
+ *
+ * struct Curl_addrinfo {
+ * int ai_flags;
+ * int ai_family;
+ * int ai_socktype;
+ * int ai_protocol;
+ * curl_socklen_t ai_addrlen; * Follow rfc3493 struct addrinfo *
+ * char *ai_canonname;
+ * struct sockaddr *ai_addr;
+ * struct Curl_addrinfo *ai_next;
+ * };
+ * typedef struct Curl_addrinfo Curl_addrinfo;
+ *
+ * hostent defined in <netdb.h>
+ *
+ * struct hostent {
+ * char *h_name;
+ * char **h_aliases;
+ * int h_addrtype;
+ * int h_length;
+ * char **h_addr_list;
+ * };
+ *
+ * for backward compatibility:
+ *
+ * #define h_addr h_addr_list[0]
+ */
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port)
+{
+ Curl_addrinfo *ai;
+ Curl_addrinfo *prevai = NULL;
+ Curl_addrinfo *firstai = NULL;
+ struct sockaddr_in *addr;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *addr6;
+#endif
+ CURLcode result = CURLE_OK;
+ int i;
+ char *curr;
+
+ if(!he)
+ /* no input == no output! */
+ return NULL;
+
+ DEBUGASSERT((he->h_name != NULL) && (he->h_addr_list != NULL));
+
+ for(i=0; (curr = he->h_addr_list[i]) != NULL; i++) {
+
+ size_t ss_size;
+#ifdef ENABLE_IPV6
+ if(he->h_addrtype == AF_INET6)
+ ss_size = sizeof (struct sockaddr_in6);
+ else
+#endif
+ ss_size = sizeof (struct sockaddr_in);
+
+ if((ai = calloc(1, sizeof(Curl_addrinfo))) == NULL) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ if((ai->ai_canonname = strdup(he->h_name)) == NULL) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai);
+ break;
+ }
+ if((ai->ai_addr = calloc(1, ss_size)) == NULL) {
+ result = CURLE_OUT_OF_MEMORY;
+ free(ai->ai_canonname);
+ free(ai);
+ break;
+ }
+
+ if(!firstai)
+ /* store the pointer we want to return from this function */
+ firstai = ai;
+
+ if(prevai)
+ /* make the previous entry point to this */
+ prevai->ai_next = ai;
+
+ ai->ai_family = he->h_addrtype;
+
+ /* we return all names as STREAM, so when using this address for TFTP
+ the type must be ignored and conn->socktype be used instead! */
+ ai->ai_socktype = SOCK_STREAM;
+
+ ai->ai_addrlen = (curl_socklen_t)ss_size;
+
+ /* leave the rest of the struct filled with zero */
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ addr = (void *)ai->ai_addr; /* storage area for this info */
+
+ memcpy(&addr->sin_addr, curr, sizeof(struct in_addr));
+ addr->sin_family = (unsigned short)(he->h_addrtype);
+ addr->sin_port = htons((unsigned short)port);
+ break;
+
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addr6 = (void *)ai->ai_addr; /* storage area for this info */
+
+ memcpy(&addr6->sin6_addr, curr, sizeof(struct in6_addr));
+ addr6->sin6_family = (unsigned short)(he->h_addrtype);
+ addr6->sin6_port = htons((unsigned short)port);
+ break;
+#endif
+ }
+
+ prevai = ai;
+ }
+
+ if(result != CURLE_OK) {
+ Curl_freeaddrinfo(firstai);
+ firstai = NULL;
+ }
+
+ return firstai;
+}
+
+
+struct namebuff {
+ struct hostent hostentry;
+ union {
+ struct in_addr ina4;
+#ifdef ENABLE_IPV6
+ struct in6_addr ina6;
+#endif
+ } addrentry;
+ char *h_addr_list[2];
+};
+
+
+/*
+ * Curl_ip2addr()
+ *
+ * This function takes an internet address, in binary form, as input parameter
+ * along with its address family and the string version of the address, and it
+ * returns a Curl_addrinfo chain filled in correctly with information for the
+ * given address/host
+ */
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port)
+{
+ Curl_addrinfo *ai;
+
+#if defined(__VMS) && \
+ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size save
+#pragma pointer_size short
+#pragma message disable PTRMISMATCH
+#endif
+
+ struct hostent *h;
+ struct namebuff *buf;
+ char *addrentry;
+ char *hoststr;
+ size_t addrsize;
+
+ DEBUGASSERT(inaddr && hostname);
+
+ buf = malloc(sizeof(struct namebuff));
+ if(!buf)
+ return NULL;
+
+ hoststr = strdup(hostname);
+ if(!hoststr) {
+ free(buf);
+ return NULL;
+ }
+
+ switch(af) {
+ case AF_INET:
+ addrsize = sizeof(struct in_addr);
+ addrentry = (void *)&buf->addrentry.ina4;
+ memcpy(addrentry, inaddr, sizeof(struct in_addr));
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ addrsize = sizeof(struct in6_addr);
+ addrentry = (void *)&buf->addrentry.ina6;
+ memcpy(addrentry, inaddr, sizeof(struct in6_addr));
+ break;
+#endif
+ default:
+ free(hoststr);
+ free(buf);
+ return NULL;
+ }
+
+ h = &buf->hostentry;
+ h->h_name = hoststr;
+ h->h_aliases = NULL;
+ h->h_addrtype = (short)af;
+ h->h_length = (short)addrsize;
+ h->h_addr_list = &buf->h_addr_list[0];
+ h->h_addr_list[0] = addrentry;
+ h->h_addr_list[1] = NULL; /* terminate list of entries */
+
+#if defined(__VMS) && \
+ defined(__INITIAL_POINTER_SIZE) && (__INITIAL_POINTER_SIZE == 64)
+#pragma pointer_size restore
+#pragma message enable PTRMISMATCH
+#endif
+
+ ai = Curl_he2ai(h, port);
+
+ free(hoststr);
+ free(buf);
+
+ return ai;
+}
+
+/*
+ * Given an IPv4 or IPv6 dotted string address, this converts it to a proper
+ * allocated Curl_addrinfo struct and returns it.
+ */
+Curl_addrinfo *Curl_str2addr(char *address, int port)
+{
+ struct in_addr in;
+ if(Curl_inet_pton(AF_INET, address, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, address, port);
+#ifdef ENABLE_IPV6
+ else {
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, address, &in6) > 0)
+ /* This is a dotted IPv6 address ::1-style */
+ return Curl_ip2addr(AF_INET6, &in6, address, port);
+ }
+#endif
+ return NULL; /* bad input format */
+}
+
+#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+/*
+ * curl_dofreeaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source)
+{
+ (freeaddrinfo)(freethis);
+ curl_memlog("ADDR %s:%d freeaddrinfo(%p)\n",
+ source, line, (void *)freethis);
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO) */
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+/*
+ * curl_dogetaddrinfo()
+ *
+ * This is strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+int
+curl_dogetaddrinfo(const char *hostname,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source)
+{
+ int res=(getaddrinfo)(hostname, service, hints, result);
+ if(0 == res)
+ /* success */
+ curl_memlog("ADDR %s:%d getaddrinfo() = %p\n",
+ source, line, (void *)*result);
+ else
+ curl_memlog("ADDR %s:%d getaddrinfo() failed\n",
+ source, line);
+ return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETADDRINFO) */
+
diff --git a/libs/libcurl/src/curl_addrinfo.h b/libs/libcurl/src/curl_addrinfo.h
new file mode 100644
index 0000000000..6d2b753eb3
--- /dev/null
+++ b/libs/libcurl/src/curl_addrinfo.h
@@ -0,0 +1,97 @@
+#ifndef HEADER_CURL_ADDRINFO_H
+#define HEADER_CURL_ADDRINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#ifdef __VMS
+# include <in.h>
+# include <inet.h>
+# include <stdlib.h>
+#endif
+
+
+/*
+ * Curl_addrinfo is our internal struct definition that we use to allow
+ * consistent internal handling of this data. We use this even when the
+ * system provides an addrinfo structure definition. And we use this for
+ * all sorts of IPv4 and IPV6 builds.
+ */
+
+struct Curl_addrinfo {
+ int ai_flags;
+ int ai_family;
+ int ai_socktype;
+ int ai_protocol;
+ curl_socklen_t ai_addrlen; /* Follow rfc3493 struct addrinfo */
+ char *ai_canonname;
+ struct sockaddr *ai_addr;
+ struct Curl_addrinfo *ai_next;
+};
+typedef struct Curl_addrinfo Curl_addrinfo;
+
+void
+Curl_freeaddrinfo(Curl_addrinfo *cahead);
+
+#ifdef HAVE_GETADDRINFO
+int
+Curl_getaddrinfo_ex(const char *nodename,
+ const char *servname,
+ const struct addrinfo *hints,
+ Curl_addrinfo **result);
+#endif
+
+Curl_addrinfo *
+Curl_he2ai(const struct hostent *he, int port);
+
+Curl_addrinfo *
+Curl_ip2addr(int af, const void *inaddr, const char *hostname, int port);
+
+Curl_addrinfo *Curl_str2addr(char *dotted, int port);
+
+#if defined(CURLDEBUG) && defined(HAVE_FREEADDRINFO)
+void
+curl_dofreeaddrinfo(struct addrinfo *freethis,
+ int line, const char *source);
+#endif
+
+#if defined(CURLDEBUG) && defined(HAVE_GETADDRINFO)
+int
+curl_dogetaddrinfo(const char *hostname,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **result,
+ int line, const char *source);
+#endif
+
+#endif /* HEADER_CURL_ADDRINFO_H */
diff --git a/libs/libcurl/src/curl_base64.h b/libs/libcurl/src/curl_base64.h
new file mode 100644
index 0000000000..6e200d2ec4
--- /dev/null
+++ b/libs/libcurl/src/curl_base64.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_BASE64_H
+#define HEADER_CURL_BASE64_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_base64_encode(struct SessionHandle *data,
+ const char *inputbuff, size_t insize,
+ char **outptr, size_t *outlen);
+
+CURLcode Curl_base64_decode(const char *src,
+ unsigned char **outptr, size_t *outlen);
+
+#endif /* HEADER_CURL_BASE64_H */
diff --git a/libs/libcurl/src/curl_darwinssl.c b/libs/libcurl/src/curl_darwinssl.c
new file mode 100644
index 0000000000..43fe053369
--- /dev/null
+++ b/libs/libcurl/src/curl_darwinssl.c
@@ -0,0 +1,2125 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012-2013, Nick Zitzmann, <nickzman@gmail.com>.
+ * Copyright (C) 2012-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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all iOS and Mac OS X SecureTransport-specific code for the
+ * TLS/SSL layer. No code but sslgen.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_DARWINSSL
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <Security/Security.h>
+#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 /* CURL_BUILD_MAC */
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "connect.h"
+#include "select.h"
+#include "sslgen.h"
+#include "curl_darwinssl.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"
+
+/* From MacTypes.h (which we can't include because it isn't present in iOS: */
+#define ioErr -36
+#define paramErr -50
+
+/* The following two functions were ripped from Apple sample code,
+ * with some modifications: */
+static OSStatus SocketRead(SSLConnectionRef connection,
+ void *data, /* owned by
+ * caller, data
+ * RETURNED */
+ size_t *dataLength) /* IN/OUT */
+{
+ size_t bytesToGo = *dataLength;
+ size_t initLen = bytesToGo;
+ UInt8 *currData = (UInt8 *)data;
+ /*int sock = *(int *)connection;*/
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ int sock = connssl->ssl_sockfd;
+ OSStatus rtn = noErr;
+ size_t bytesRead;
+ ssize_t rrtn;
+ int theErr;
+
+ *dataLength = 0;
+
+ for(;;) {
+ bytesRead = 0;
+ rrtn = read(sock, currData, bytesToGo);
+ if(rrtn <= 0) {
+ /* this is guesswork... */
+ theErr = errno;
+ if(rrtn == 0) { /* EOF = server hung up */
+ /* the framework will turn this into errSSLClosedNoNotify */
+ rtn = errSSLClosedGraceful;
+ }
+ else /* do the switch */
+ switch(theErr) {
+ case ENOENT:
+ /* connection closed */
+ rtn = errSSLClosedGraceful;
+ break;
+ case ECONNRESET:
+ rtn = errSSLClosedAbort;
+ break;
+ case EAGAIN:
+ rtn = errSSLWouldBlock;
+ connssl->ssl_direction = false;
+ break;
+ default:
+ rtn = ioErr;
+ break;
+ }
+ break;
+ }
+ else {
+ bytesRead = rrtn;
+ }
+ bytesToGo -= bytesRead;
+ currData += bytesRead;
+
+ if(bytesToGo == 0) {
+ /* filled buffer with incoming data, done */
+ break;
+ }
+ }
+ *dataLength = initLen - bytesToGo;
+
+ return rtn;
+}
+
+static OSStatus SocketWrite(SSLConnectionRef connection,
+ const void *data,
+ size_t *dataLength) /* IN/OUT */
+{
+ size_t bytesSent = 0;
+ /*int sock = *(int *)connection;*/
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)connection;
+ int sock = connssl->ssl_sockfd;
+ ssize_t length;
+ size_t dataLen = *dataLength;
+ const UInt8 *dataPtr = (UInt8 *)data;
+ OSStatus ortn;
+ int theErr;
+
+ *dataLength = 0;
+
+ do {
+ length = write(sock,
+ (char*)dataPtr + bytesSent,
+ dataLen - bytesSent);
+ } while((length > 0) &&
+ ( (bytesSent += length) < dataLen) );
+
+ if(length <= 0) {
+ theErr = errno;
+ if(theErr == EAGAIN) {
+ ortn = errSSLWouldBlock;
+ connssl->ssl_direction = true;
+ }
+ else {
+ ortn = ioErr;
+ }
+ }
+ else {
+ ortn = noErr;
+ }
+ *dataLength = bytesSent;
+ return ortn;
+}
+
+CF_INLINE const char *SSLCipherNameForNumber(SSLCipherSuite cipher) {
+ switch (cipher) {
+ /* SSL version 3.0 */
+ case SSL_RSA_WITH_NULL_MD5:
+ return "SSL_RSA_WITH_NULL_MD5";
+ break;
+ case SSL_RSA_WITH_NULL_SHA:
+ return "SSL_RSA_WITH_NULL_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ return "SSL_RSA_EXPORT_WITH_RC4_40_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_MD5:
+ return "SSL_RSA_WITH_RC4_128_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_SHA:
+ return "SSL_RSA_WITH_RC4_128_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ return "SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5";
+ break;
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ return "SSL_RSA_WITH_IDEA_CBC_SHA";
+ break;
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ return "SSL_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ return "SSL_DH_DSS_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ return "SSL_DH_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ return "SSL_DHE_DSS_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ return "SSL_DHE_RSA_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_anon_EXPORT_WITH_RC4_40_MD5:
+ return "SSL_DH_anon_EXPORT_WITH_RC4_40_MD5";
+ break;
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ return "SSL_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ return "SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ return "SSL_DH_anon_WITH_DES_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "SSL_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_FORTEZZA_DMS_WITH_NULL_SHA:
+ return "SSL_FORTEZZA_DMS_WITH_NULL_SHA";
+ break;
+ case SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA:
+ return "SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA";
+ break;
+ /* TLS 1.0 with AES (RFC 3268)
+ (Apparently these are used in SSLv3 implementations as well.) */
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+ break;
+ /* SSL version 2.0 */
+ case SSL_RSA_WITH_RC2_CBC_MD5:
+ return "SSL_RSA_WITH_RC2_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ return "SSL_RSA_WITH_IDEA_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_DES_CBC_MD5:
+ return "SSL_RSA_WITH_DES_CBC_MD5";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_MD5:
+ return "SSL_RSA_WITH_3DES_EDE_CBC_MD5";
+ break;
+ }
+ return "SSL_NULL_WITH_NULL_NULL";
+}
+
+CF_INLINE const char *TLSCipherNameForNumber(SSLCipherSuite cipher) {
+ switch(cipher) {
+ /* TLS 1.0 with AES (RFC 3268) */
+ case TLS_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA";
+ break;
+#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";
+ break;
+ case TLS_ECDH_ECDSA_WITH_RC4_128_SHA:
+ return "TLS_ECDH_ECDSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_NULL_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_RC4_128_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_NULL_SHA:
+ return "TLS_ECDH_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_RC4_128_SHA:
+ return "TLS_ECDH_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_NULL_SHA:
+ return "TLS_ECDHE_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_RC4_128_SHA:
+ return "TLS_ECDHE_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_NULL_SHA:
+ return "TLS_ECDH_anon_WITH_NULL_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_RC4_128_SHA:
+ return "TLS_ECDH_anon_WITH_RC4_128_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_AES_128_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_AES_128_CBC_SHA";
+ break;
+ case TLS_ECDH_anon_WITH_AES_256_CBC_SHA:
+ return "TLS_ECDH_anon_WITH_AES_256_CBC_SHA";
+ break;
+#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";
+ break;
+ case TLS_RSA_WITH_NULL_SHA:
+ return "TLS_RSA_WITH_NULL_SHA";
+ break;
+ case TLS_RSA_WITH_RC4_128_MD5:
+ return "TLS_RSA_WITH_RC4_128_MD5";
+ break;
+ case TLS_RSA_WITH_RC4_128_SHA:
+ return "TLS_RSA_WITH_RC4_128_SHA";
+ break;
+ case TLS_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_RSA_WITH_NULL_SHA256:
+ return "TLS_RSA_WITH_NULL_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_DSS_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_CBC_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_DSS_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_CBC_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_CBC_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256";
+ break;
+ case TLS_DH_anon_WITH_RC4_128_MD5:
+ return "TLS_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case TLS_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA256:
+ return "TLS_DH_anon_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA256:
+ return "TLS_DH_anon_WITH_AES_256_CBC_SHA256";
+ break;
+ /* TLS 1.2 with AES GCM (RFC 5288) */
+ case TLS_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DHE_DSS_WITH_AES_128_GCM_SHA256:
+ return "TLS_DHE_DSS_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DHE_DSS_WITH_AES_256_GCM_SHA384:
+ return "TLS_DHE_DSS_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_DSS_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_DSS_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_DSS_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_DSS_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_DH_anon_WITH_AES_128_GCM_SHA256:
+ return "TLS_DH_anon_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_DH_anon_WITH_AES_256_GCM_SHA384:
+ return "TLS_DH_anon_WITH_AES_256_GCM_SHA384";
+ break;
+ /* TLS 1.2 with elliptic curve ciphers (RFC 5289) */
+ case TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256:
+ return "TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384:
+ return "TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256:
+ return "TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256";
+ break;
+ case TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384:
+ return "TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384";
+ break;
+ case TLS_EMPTY_RENEGOTIATION_INFO_SCSV:
+ return "TLS_EMPTY_RENEGOTIATION_INFO_SCSV";
+ break;
+#else
+ case SSL_RSA_WITH_NULL_MD5:
+ return "TLS_RSA_WITH_NULL_MD5";
+ break;
+ case SSL_RSA_WITH_NULL_SHA:
+ return "TLS_RSA_WITH_NULL_SHA";
+ break;
+ case SSL_RSA_WITH_RC4_128_MD5:
+ return "TLS_RSA_WITH_RC4_128_MD5";
+ break;
+ case SSL_RSA_WITH_RC4_128_SHA:
+ return "TLS_RSA_WITH_RC4_128_SHA";
+ break;
+ case SSL_RSA_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_RSA_WITH_3DES_EDE_CBC_SHA";
+ break;
+ case SSL_DH_anon_WITH_RC4_128_MD5:
+ return "TLS_DH_anon_WITH_RC4_128_MD5";
+ break;
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ return "TLS_DH_anon_WITH_3DES_EDE_CBC_SHA";
+ break;
+#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 CURL_BUILD_MAC
+CF_INLINE void GetDarwinVersionNumber(int *major, int *minor)
+{
+ int mib[2];
+ char *os_version;
+ size_t os_version_len;
+ char *os_version_major, *os_version_minor/*, *os_version_point*/;
+
+ /* Get the Darwin kernel version from the kernel using sysctl(): */
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_OSRELEASE;
+ if(sysctl(mib, 2, NULL, &os_version_len, NULL, 0) == -1)
+ return;
+ os_version = malloc(os_version_len*sizeof(char));
+ if(!os_version)
+ return;
+ if(sysctl(mib, 2, os_version, &os_version_len, NULL, 0) == -1) {
+ free(os_version);
+ return;
+ }
+
+ /* Parse the version: */
+ os_version_major = strtok(os_version, ".");
+ os_version_minor = strtok(NULL, ".");
+ /*os_version_point = strtok(NULL, ".");*/
+ *major = atoi(os_version_major);
+ *minor = atoi(os_version_minor);
+ free(os_version);
+}
+#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
+ a unified function for getting a string describing the certificate that
+ ought to work in all cats starting with Leopard. */
+CF_INLINE CFStringRef CopyCertSubject(SecCertificateRef cert)
+{
+ CFStringRef server_cert_summary = CFSTR("(null)");
+
+#if CURL_BUILD_IOS
+ /* iOS: There's only one way to do this. */
+ server_cert_summary = SecCertificateCopySubjectSummary(cert);
+#else
+#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 /* 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 /* CURL_BUILD_MAC_10_6 */
+ /* Leopard is as far back as we go... */
+ (void)SecCertificateCopyCommonName(cert, &server_cert_summary);
+#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)
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#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 CURL_BUILD_MAC
+ int darwinver_maj = 0, darwinver_min = 0;
+
+ GetDarwinVersionNumber(&darwinver_maj, &darwinver_min);
+#endif /* CURL_BUILD_MAC */
+
+#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);
+ connssl->ssl_ctx = SSLCreateContext(NULL, kSSLClientSide, kSSLStreamType);
+ if(!connssl->ssl_ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else {
+ /* The old ST API does not exist under iOS, so don't compile it: */
+#if CURL_SUPPORT_MAC_10_8
+ if(connssl->ssl_ctx)
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+ err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(err != noErr) {
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ if(connssl->ssl_ctx)
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+ err = SSLNewContext(false, &(connssl->ssl_ctx));
+ if(err != noErr) {
+ failf(data, "SSL: couldn't create a context: OSStatus %d", err);
+ return CURLE_OUT_OF_MEMORY;
+ }
+#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 CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLSetProtocolVersionMax != NULL) {
+ switch(data->set.ssl.version) {
+ case CURL_SSLVERSION_DEFAULT: default:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kTLSProtocol1);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kTLSProtocol12);
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ (void)SSLSetProtocolVersionMin(connssl->ssl_ctx, kSSLProtocol3);
+ (void)SSLSetProtocolVersionMax(connssl->ssl_ctx, kSSLProtocol3);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ 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 CURL_SUPPORT_MAC_10_8
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocolAll,
+ false);
+ switch (data->set.ssl.version) {
+ case CURL_SSLVERSION_DEFAULT: default:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol11,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol12,
+ true);
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ 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 /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx, kSSLProtocolAll, false);
+ switch(data->set.ssl.version) {
+ default:
+ case CURL_SSLVERSION_DEFAULT:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kSSLProtocol3,
+ true);
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ (void)SSLSetProtocolVersionEnabled(connssl->ssl_ctx,
+ kTLSProtocol1,
+ true);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ 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,
+ kSSLProtocol3,
+ true);
+ break;
+ }
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+
+ 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 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.
+ So we need to call SSLSetEnableCertVerify() on those older cats in order
+ to disable certificate validation if the user turned that off.
+ (SecureTransport will always validate the certificate chain by
+ default.) */
+ /* (Note: Darwin 12.x.x is Mountain Lion.) */
+#if CURL_BUILD_MAC
+ if(SSLSetSessionOption != NULL && darwinver_maj >= 12) {
+#else
+ if(SSLSetSessionOption != NULL) {
+#endif /* CURL_BUILD_MAC */
+ err = SSLSetSessionOption(connssl->ssl_ctx,
+ kSSLSessionOptionBreakOnServerAuth,
+ data->set.ssl.verifypeer?false:true);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetSessionOption() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+#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 /* CURL_SUPPORT_MAC_10_8 */
+ }
+#else
+ 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 /* 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 */
+ /* If this is a domain name and not an IP address, then configure SNI: */
+ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+#endif
+ data->set.ssl.verifyhost) {
+ err = SSLSetPeerDomainName(connssl->ssl_ctx, conn->host.name,
+ strlen(conn->host.name));
+ if(err != noErr) {
+ infof(data, "WARNING: SSL: SSLSetPeerDomainName() failed: OSStatus %d\n",
+ err);
+ }
+ }
+
+ /* Disable cipher suites that ST supports but are not safe. These ciphers
+ are unlikely to be used in any case since ST gives other ciphers a much
+ higher priority, but it's probably better that we not connect at all than
+ to give the user a false sense of security if the server only supports
+ insecure ciphers. (Note: We don't care about SSLv2-only ciphers.) */
+ (void)SSLGetNumberSupportedCiphers(connssl->ssl_ctx, &all_ciphers_count);
+ all_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ allowed_ciphers = malloc(all_ciphers_count*sizeof(SSLCipherSuite));
+ if(all_ciphers && allowed_ciphers &&
+ SSLGetSupportedCiphers(connssl->ssl_ctx, all_ciphers,
+ &all_ciphers_count) == noErr) {
+ for(i = 0UL ; i < all_ciphers_count ; i++) {
+#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
+ running in an affected version of OS X. */
+ if(darwinver_maj == 12 && darwinver_min <= 3 &&
+ all_ciphers[i] >= 0xC001 && all_ciphers[i] <= 0xC032) {
+ continue;
+ }
+#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:
+ case SSL_DH_anon_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_anon_WITH_DES_CBC_SHA:
+ case SSL_DH_anon_WITH_3DES_EDE_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_128_CBC_SHA:
+ case TLS_DH_anon_WITH_AES_256_CBC_SHA:
+ case 0xC015: /* TLS_ECDH_anon_WITH_NULL_SHA */
+ case 0xC016: /* TLS_ECDH_anon_WITH_RC4_128_SHA */
+ case 0xC017: /* TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA */
+ case 0xC018: /* TLS_ECDH_anon_WITH_AES_128_CBC_SHA */
+ case 0xC019: /* TLS_ECDH_anon_WITH_AES_256_CBC_SHA */
+ case 0x006C: /* TLS_DH_anon_WITH_AES_128_CBC_SHA256 */
+ case 0x006D: /* TLS_DH_anon_WITH_AES_256_CBC_SHA256 */
+ case 0x00A6: /* TLS_DH_anon_WITH_AES_128_GCM_SHA256 */
+ case 0x00A7: /* TLS_DH_anon_WITH_AES_256_GCM_SHA384 */
+ /* Disable weak key ciphersuites: */
+ case SSL_RSA_EXPORT_WITH_RC4_40_MD5:
+ case SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5:
+ case SSL_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DH_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA:
+ case SSL_RSA_WITH_DES_CBC_SHA:
+ case SSL_DH_DSS_WITH_DES_CBC_SHA:
+ case SSL_DH_RSA_WITH_DES_CBC_SHA:
+ case SSL_DHE_DSS_WITH_DES_CBC_SHA:
+ case SSL_DHE_RSA_WITH_DES_CBC_SHA:
+ /* Disable IDEA: */
+ case SSL_RSA_WITH_IDEA_CBC_SHA:
+ case SSL_RSA_WITH_IDEA_CBC_MD5:
+ break;
+ default: /* enable everything else */
+ allowed_ciphers[allowed_ciphers_count++] = all_ciphers[i];
+ break;
+ }
+ }
+ err = SSLSetEnabledCiphers(connssl->ssl_ctx, allowed_ciphers,
+ allowed_ciphers_count);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetEnabledCiphers() failed: OSStatus %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ Curl_safefree(all_ciphers);
+ Curl_safefree(allowed_ciphers);
+ failf(data, "SSL: Failed to allocate memory for allowed ciphers");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ 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);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* pass the raw socket into the SSL layers */
+ /* We need to store the FD in a constant memory address, because
+ * SSLSetConnection() will not copy that address. I've found that
+ * conn->sock[sockindex] may change on its own. */
+ connssl->ssl_sockfd = sockfd;
+ err = SSLSetConnection(connssl->ssl_ctx, connssl);
+ if(err != noErr) {
+ failf(data, "SSL: SSLSetConnection() failed: %d", err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+static CURLcode
+darwinssl_connect_step2(struct connectdata *conn, int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ OSStatus err;
+ SSLCipherSuite cipher;
+ SSLProtocol protocol = 0;
+
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
+
+ /* Here goes nothing: */
+ err = SSLHandshake(connssl->ssl_ctx);
+
+ if(err != noErr) {
+ switch (err) {
+ case errSSLWouldBlock: /* they're not done with us yet */
+ connssl->connecting_state = connssl->ssl_direction ?
+ ssl_connect_2_writing : ssl_connect_2_reading;
+ return CURLE_OK;
+
+ /* The below is errSSLServerAuthCompleted; it's not defined in
+ Leopard's headers */
+ case -9841:
+ /* the documentation says we need to call SSLHandshake() again */
+ return darwinssl_connect_step2(conn, sockindex);
+
+ /* These are all certificate problems with the server: */
+ case errSSLXCertChainInvalid:
+ failf(data, "SSL certificate problem: Invalid certificate chain");
+ return CURLE_SSL_CACERT;
+ case errSSLUnknownRootCert:
+ failf(data, "SSL certificate problem: Untrusted root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLNoRootCert:
+ failf(data, "SSL certificate problem: No root certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLCertExpired:
+ failf(data, "SSL certificate problem: Certificate chain had an "
+ "expired certificate");
+ return CURLE_SSL_CACERT;
+ case errSSLBadCert:
+ failf(data, "SSL certificate problem: Couldn't understand the server "
+ "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:
+ failf(data, "SSL certificate peer verification failed, the "
+ "certificate did not match \"%s\"\n", conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ /* Generic handshake errors: */
+ case errSSLConnectionRefused:
+ failf(data, "Server dropped the connection during the SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLClosedAbort:
+ failf(data, "Server aborted the SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLNegotiation:
+ failf(data, "Could not negotiate an SSL cipher suite with the server");
+ return CURLE_SSL_CONNECT_ERROR;
+ /* Sometimes paramErr happens with buggy ciphers: */
+ case paramErr: case errSSLInternal:
+ failf(data, "Internal SSL engine error encountered during the "
+ "SSL handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ case errSSLFatalAlert:
+ failf(data, "Fatal SSL engine error encountered during the SSL "
+ "handshake");
+ return CURLE_SSL_CONNECT_ERROR;
+ default:
+ failf(data, "Unknown SSL protocol error in connection to %s:%d",
+ conn->host.name, err);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+ else {
+ /* we have been connected fine, we're not waiting for anything else. */
+ connssl->connecting_state = ssl_connect_3;
+
+ /* Informational message */
+ (void)SSLGetNegotiatedCipher(connssl->ssl_ctx, &cipher);
+ (void)SSLGetNegotiatedProtocolVersion(connssl->ssl_ctx, &protocol);
+ switch (protocol) {
+ case kSSLProtocol2:
+ infof(data, "SSL 2.0 connection using %s\n",
+ SSLCipherNameForNumber(cipher));
+ break;
+ case kSSLProtocol3:
+ infof(data, "SSL 3.0 connection using %s\n",
+ SSLCipherNameForNumber(cipher));
+ break;
+ case kTLSProtocol1:
+ infof(data, "TLS 1.0 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ case kTLSProtocol11:
+ infof(data, "TLS 1.1 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+ case kTLSProtocol12:
+ infof(data, "TLS 1.2 connection using %s\n",
+ TLSCipherNameForNumber(cipher));
+ break;
+#endif
+ default:
+ infof(data, "Unknown protocol connection\n");
+ break;
+ }
+
+ return CURLE_OK;
+ }
+}
+
+static CURLcode
+darwinssl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CFStringRef server_cert_summary;
+ char server_cert_summary_c[128];
+ CFArrayRef server_certs = NULL;
+ SecCertificateRef server_cert;
+ OSStatus err;
+ CFIndex i, count;
+ 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 CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS
+#if CURL_BUILD_IOS
+#pragma unused(server_certs)
+ err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ /* 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);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(trust);
+ }
+#else
+ /* SSLCopyPeerCertificates() is deprecated as of Mountain Lion.
+ The function SecTrustGetCertificateAtIndex() is officially present
+ in Lion, but it is unfortunately also present in Snow Leopard as
+ private API and doesn't work as expected. So we have to look for
+ a different symbol to make sure this code is only executed under
+ Lion or later. */
+ if(SecTrustEvaluateAsync != NULL) {
+#pragma unused(server_certs)
+ err = SSLCopyPeerTrust(connssl->ssl_ctx, &trust);
+ /* 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);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(trust);
+ }
+ }
+ else {
+#if CURL_SUPPORT_MAC_10_8
+ err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ /* 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,
+ i);
+
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(server_certs);
+ }
+#endif /* CURL_SUPPORT_MAC_10_8 */
+ }
+#endif /* CURL_BUILD_IOS */
+#else
+#pragma unused(trust)
+ err = SSLCopyPeerCertificates(connssl->ssl_ctx, &server_certs);
+ if(err == noErr) {
+ count = CFArrayGetCount(server_certs);
+ for(i = 0L ; i < count ; i++) {
+ server_cert = (SecCertificateRef)CFArrayGetValueAtIndex(server_certs, i);
+ server_cert_summary = CopyCertSubject(server_cert);
+ memset(server_cert_summary_c, 0, 128);
+ if(CFStringGetCString(server_cert_summary,
+ server_cert_summary_c,
+ 128,
+ kCFStringEncodingUTF8)) {
+ infof(data, "Server certificate: %s\n", server_cert_summary_c);
+ }
+ CFRelease(server_cert_summary);
+ }
+ CFRelease(server_certs);
+ }
+#endif /* CURL_BUILD_MAC_10_7 || CURL_BUILD_IOS */
+
+ connssl->connecting_state = ssl_connect_done;
+ return CURLE_OK;
+}
+
+static Curl_recv darwinssl_recv;
+static Curl_send darwinssl_send;
+
+static CURLcode
+darwinssl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ retcode = darwinssl_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if this
+ * connection is done nonblocking and this loop would execute again. This
+ * permits the owner of a multi handle to abort a connection attempt
+ * before step2 has completed while ensuring that a client using select()
+ * or epoll() will always have a valid fdset to wait on.
+ */
+ retcode = darwinssl_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+
+ if(ssl_connect_3==connssl->connecting_state) {
+ retcode = darwinssl_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done==connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = darwinssl_recv;
+ conn->send[sockindex] = darwinssl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return darwinssl_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_darwinssl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = darwinssl_connect_common(conn, sockindex, FALSE, &done);
+
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+void Curl_darwinssl_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->ssl_ctx) {
+ (void)SSLClose(connssl->ssl_ctx);
+#if CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS
+ if(SSLCreateContext != NULL)
+ CFRelease(connssl->ssl_ctx);
+#if CURL_SUPPORT_MAC_10_8
+ else
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+#endif /* CURL_SUPPORT_MAC_10_8 */
+#else
+ (void)SSLDisposeContext(connssl->ssl_ctx);
+#endif /* CURL_BUILD_MAC_10_8 || CURL_BUILD_IOS */
+ connssl->ssl_ctx = NULL;
+ }
+ connssl->ssl_sockfd = 0;
+}
+
+void Curl_darwinssl_close_all(struct SessionHandle *data)
+{
+ /* SecureTransport doesn't separate sessions from contexts, so... */
+ (void)data;
+}
+
+int Curl_darwinssl_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->ssl_ctx)
+ return 0;
+
+ if(data->set.ftp_ccc != CURLFTPSSL_CCC_ACTIVE)
+ return 0;
+
+ Curl_darwinssl_close(conn, sockindex);
+
+ 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 SSL_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;
+}
+
+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");
+}
+
+/*
+ * This function uses SSLGetSessionState to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_darwinssl_check_cxn(struct connectdata *conn)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+ OSStatus err;
+ SSLSessionState state;
+
+ if(connssl->ssl_ctx) {
+ err = SSLGetSessionState(connssl->ssl_ctx, &state);
+ if(err == noErr)
+ return state == kSSLConnected || state == kSSLHandshake;
+ return -1;
+ }
+ return 0;
+}
+
+bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+ int connindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[connindex];
+ OSStatus err;
+ size_t buffer;
+
+ if(connssl->ssl_ctx) { /* SSL is in use */
+ err = SSLGetBufferedReadSize(connssl->ssl_ctx, &buffer);
+ if(err == noErr)
+ return buffer > 0UL;
+ return false;
+ }
+ else
+ return false;
+}
+
+void Curl_darwinssl_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ /* arc4random_buf() isn't available on cats older than Lion, so let's
+ do this manually for the benefit of the older cats. */
+ size_t i;
+ u_int32_t random_number = 0;
+
+ for(i = 0 ; i < length ; i++) {
+ if(i % sizeof(u_int32_t) == 0)
+ random_number = arc4random();
+ entropy[i] = random_number & 0xFF;
+ random_number >>= 8;
+ }
+ i = random_number = 0;
+ (void)data;
+}
+
+void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+ (void)md5len;
+ (void)CC_MD5(tmp, (CC_LONG)tmplen, md5sum);
+}
+
+static ssize_t darwinssl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ /*struct SessionHandle *data = conn->data;*/
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ size_t processed = 0UL;
+ OSStatus err;
+
+ /* The SSLWrite() function works a little differently than expected. The
+ fourth argument (processed) is currently documented in Apple's
+ documentation as: "On return, the length, in bytes, of the data actually
+ written."
+
+ Now, one could interpret that as "written to the socket," but actually,
+ it returns the amount of data that was written to a buffer internal to
+ the SSLContextRef instead. So it's possible for SSLWrite() to return
+ errSSLWouldBlock and a number of bytes "written" because those bytes were
+ encrypted and written to a buffer, not to the socket.
+
+ So if this happens, then we need to keep calling SSLWrite() over and
+ over again with no new data until it quits returning errSSLWouldBlock. */
+
+ /* Do we have buffered data to write from the last time we were called? */
+ if(connssl->ssl_write_buffered_length) {
+ /* Write the buffered data: */
+ err = SSLWrite(connssl->ssl_ctx, NULL, 0UL, &processed);
+ switch (err) {
+ case noErr:
+ /* processed is always going to be 0 because we didn't write to
+ the buffer, so return how much was written to the socket */
+ processed = connssl->ssl_write_buffered_length;
+ connssl->ssl_write_buffered_length = 0UL;
+ break;
+ case errSSLWouldBlock: /* argh, try again */
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ default:
+ failf(conn->data, "SSLWrite() returned error %d", err);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1L;
+ }
+ }
+ else {
+ /* We've got new data to write: */
+ err = SSLWrite(connssl->ssl_ctx, mem, len, &processed);
+ if(err != noErr) {
+ switch (err) {
+ case errSSLWouldBlock:
+ /* Data was buffered but not sent, we have to tell the caller
+ to try sending again, and remember how much was buffered */
+ connssl->ssl_write_buffered_length = len;
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ default:
+ failf(conn->data, "SSLWrite() returned error %d", err);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1L;
+ }
+ }
+ }
+ return (ssize_t)processed;
+}
+
+static ssize_t darwinssl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ /*struct SessionHandle *data = conn->data;*/
+ struct ssl_connect_data *connssl = &conn->ssl[num];
+ size_t processed = 0UL;
+ OSStatus err = SSLRead(connssl->ssl_ctx, buf, buffersize, &processed);
+
+ if(err != noErr) {
+ switch (err) {
+ case errSSLWouldBlock: /* return how much we read (if anything) */
+ if(processed)
+ return (ssize_t)processed;
+ *curlcode = CURLE_AGAIN;
+ return -1L;
+ break;
+
+ /* errSSLClosedGraceful - server gracefully shut down the SSL session
+ errSSLClosedNoNotify - server hung up on us instead of sending a
+ closure alert notice, read() is returning 0
+ Either way, inform the caller that the server disconnected. */
+ case errSSLClosedGraceful:
+ case errSSLClosedNoNotify:
+ *curlcode = CURLE_OK;
+ return -1L;
+ break;
+
+ default:
+ failf(conn->data, "SSLRead() return error %d", err);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1L;
+ break;
+ }
+ }
+ return (ssize_t)processed;
+}
+
+#endif /* USE_DARWINSSL */
diff --git a/libs/libcurl/src/curl_darwinssl.h b/libs/libcurl/src/curl_darwinssl.h
new file mode 100644
index 0000000000..432d3d7ce4
--- /dev/null
+++ b/libs/libcurl/src/curl_darwinssl.h
@@ -0,0 +1,78 @@
+#ifndef HEADER_CURL_DARWINSSL_H
+#define HEADER_CURL_DARWINSSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * 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
+ * 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_DARWINSSL
+
+CURLcode Curl_darwinssl_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_darwinssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* this function doesn't actually do anything */
+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);
+bool Curl_darwinssl_data_pending(const struct connectdata *conn,
+ int connindex);
+
+void Curl_darwinssl_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length);
+void Curl_darwinssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ 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_darwinssl_session_free(x)
+#define curlssl_close_all Curl_darwinssl_close_all
+#define curlssl_close Curl_darwinssl_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_darwinssl_version
+#define curlssl_check_cxn Curl_darwinssl_check_cxn
+#define curlssl_data_pending(x,y) Curl_darwinssl_data_pending(x, y)
+#define curlssl_random(x,y,z) Curl_darwinssl_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_darwinssl_md5sum(a,b,c,d)
+
+#endif /* USE_DARWINSSL */
+#endif /* HEADER_CURL_DARWINSSL_H */
diff --git a/libs/libcurl/src/curl_fnmatch.c b/libs/libcurl/src/curl_fnmatch.c
new file mode 100644
index 0000000000..63f67b9aa2
--- /dev/null
+++ b/libs/libcurl/src/curl_fnmatch.c
@@ -0,0 +1,427 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "curl_fnmatch.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"
+
+#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
+#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
+
+#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
+
+#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
+#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
+#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
+#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
+#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
+#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
+#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
+#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
+#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
+#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
+
+typedef enum {
+ CURLFNM_LOOP_DEFAULT = 0,
+ CURLFNM_LOOP_BACKSLASH
+} loop_state;
+
+typedef enum {
+ CURLFNM_SCHS_DEFAULT = 0,
+ CURLFNM_SCHS_MAYRANGE,
+ CURLFNM_SCHS_MAYRANGE2,
+ CURLFNM_SCHS_RIGHTBR,
+ CURLFNM_SCHS_RIGHTBRLEFTBR
+} setcharset_state;
+
+typedef enum {
+ CURLFNM_PKW_INIT = 0,
+ CURLFNM_PKW_DDOT
+} parsekey_state;
+
+#define SETCHARSET_OK 1
+#define SETCHARSET_FAIL 0
+
+static int parsekeyword(unsigned char **pattern, unsigned char *charset)
+{
+ parsekey_state state = CURLFNM_PKW_INIT;
+#define KEYLEN 10
+ char keyword[KEYLEN] = { 0 };
+ int found = FALSE;
+ int i;
+ unsigned char *p = *pattern;
+ for(i = 0; !found; i++) {
+ char c = *p++;
+ if(i >= KEYLEN)
+ return SETCHARSET_FAIL;
+ switch(state) {
+ case CURLFNM_PKW_INIT:
+ if(ISALPHA(c) && ISLOWER(c))
+ keyword[i] = c;
+ else if(c == ':')
+ state = CURLFNM_PKW_DDOT;
+ else
+ return 0;
+ break;
+ case CURLFNM_PKW_DDOT:
+ if(c == ']')
+ found = TRUE;
+ else
+ return SETCHARSET_FAIL;
+ }
+ }
+#undef KEYLEN
+
+ *pattern = p; /* move caller's pattern pointer */
+ if(strcmp(keyword, "digit") == 0)
+ charset[CURLFNM_DIGIT] = 1;
+ else if(strcmp(keyword, "alnum") == 0)
+ charset[CURLFNM_ALNUM] = 1;
+ else if(strcmp(keyword, "alpha") == 0)
+ charset[CURLFNM_ALPHA] = 1;
+ else if(strcmp(keyword, "xdigit") == 0)
+ charset[CURLFNM_XDIGIT] = 1;
+ else if(strcmp(keyword, "print") == 0)
+ charset[CURLFNM_PRINT] = 1;
+ else if(strcmp(keyword, "graph") == 0)
+ charset[CURLFNM_GRAPH] = 1;
+ else if(strcmp(keyword, "space") == 0)
+ charset[CURLFNM_SPACE] = 1;
+ else if(strcmp(keyword, "blank") == 0)
+ charset[CURLFNM_BLANK] = 1;
+ else if(strcmp(keyword, "upper") == 0)
+ charset[CURLFNM_UPPER] = 1;
+ else if(strcmp(keyword, "lower") == 0)
+ charset[CURLFNM_LOWER] = 1;
+ else
+ return SETCHARSET_FAIL;
+ return SETCHARSET_OK;
+}
+
+/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
+static int setcharset(unsigned char **p, unsigned char *charset)
+{
+ setcharset_state state = CURLFNM_SCHS_DEFAULT;
+ unsigned char rangestart = 0;
+ unsigned char lastchar = 0;
+ bool something_found = FALSE;
+ unsigned char c;
+ for(;;) {
+ c = **p;
+ switch(state) {
+ case CURLFNM_SCHS_DEFAULT:
+ if(ISALNUM(c)) { /* ASCII value */
+ rangestart = c;
+ charset[c] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_MAYRANGE;
+ something_found = TRUE;
+ }
+ else if(c == ']') {
+ if(something_found)
+ return SETCHARSET_OK;
+ else
+ something_found = TRUE;
+ state = CURLFNM_SCHS_RIGHTBR;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '[') {
+ char c2 = *((*p)+1);
+ if(c2 == ':') { /* there has to be a keyword */
+ (*p) += 2;
+ if(parsekeyword(p, charset)) {
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else {
+ charset[c] = 1;
+ (*p)++;
+ }
+ something_found = TRUE;
+ }
+ else if(c == '?' || c == '*') {
+ something_found = TRUE;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '^' || c == '!') {
+ if(!something_found) {
+ if(charset[CURLFNM_NEGATE]) {
+ charset[c] = 1;
+ something_found = TRUE;
+ }
+ else
+ charset[CURLFNM_NEGATE] = 1; /* negate charset */
+ }
+ else
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT((c))) {
+ something_found = TRUE;
+ state = CURLFNM_SCHS_MAYRANGE;
+ charset[c] = 1;
+ rangestart = c;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else if(c == '\0') {
+ return SETCHARSET_FAIL;
+ }
+ else {
+ charset[c] = 1;
+ (*p)++;
+ something_found = TRUE;
+ }
+ break;
+ case CURLFNM_SCHS_MAYRANGE:
+ if(c == '-') {
+ charset[c] = 1;
+ (*p)++;
+ lastchar = '-';
+ state = CURLFNM_SCHS_MAYRANGE2;
+ }
+ else if(c == '[') {
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else if(ISALNUM(c)) {
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT(c)) {
+ charset[c] = 1;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ else if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else
+ return SETCHARSET_FAIL;
+ break;
+ case CURLFNM_SCHS_MAYRANGE2:
+ if(c == '\\') {
+ c = *(++(*p));
+ if(!ISPRINT(c))
+ return SETCHARSET_FAIL;
+ }
+ if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else if(c == '\\') {
+ c = *(++(*p));
+ if(ISPRINT(c)) {
+ charset[c] = 1;
+ state = CURLFNM_SCHS_DEFAULT;
+ (*p)++;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ if(c >= rangestart) {
+ if((ISLOWER(c) && ISLOWER(rangestart)) ||
+ (ISDIGIT(c) && ISDIGIT(rangestart)) ||
+ (ISUPPER(c) && ISUPPER(rangestart))) {
+ charset[lastchar] = 0;
+ rangestart++;
+ while(rangestart++ <= c)
+ charset[rangestart-1] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ return SETCHARSET_FAIL;
+ }
+ break;
+ case CURLFNM_SCHS_RIGHTBR:
+ if(c == '[') {
+ state = CURLFNM_SCHS_RIGHTBRLEFTBR;
+ charset[c] = 1;
+ (*p)++;
+ }
+ else if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else if(c == '\0') {
+ return SETCHARSET_FAIL;
+ }
+ else if(ISPRINT(c)) {
+ charset[c] = 1;
+ (*p)++;
+ state = CURLFNM_SCHS_DEFAULT;
+ }
+ else
+ /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
+ * nonsense warning 'statement not reached' at end of the fnc when
+ * compiling on Solaris */
+ goto fail;
+ break;
+ case CURLFNM_SCHS_RIGHTBRLEFTBR:
+ if(c == ']') {
+ return SETCHARSET_OK;
+ }
+ else {
+ state = CURLFNM_SCHS_DEFAULT;
+ charset[c] = 1;
+ (*p)++;
+ }
+ break;
+ }
+ }
+fail:
+ return SETCHARSET_FAIL;
+}
+
+static int loop(const unsigned char *pattern, const unsigned char *string)
+{
+ loop_state state = CURLFNM_LOOP_DEFAULT;
+ unsigned char *p = (unsigned char *)pattern;
+ unsigned char *s = (unsigned char *)string;
+ unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
+ int rc = 0;
+
+ for(;;) {
+ switch(state) {
+ case CURLFNM_LOOP_DEFAULT:
+ if(*p == '*') {
+ while(*(p+1) == '*') /* eliminate multiple stars */
+ p++;
+ if(*s == '\0' && *(p+1) == '\0')
+ return CURL_FNMATCH_MATCH;
+ rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
+ if(rc == CURL_FNMATCH_MATCH)
+ return CURL_FNMATCH_MATCH;
+ if(*s) /* let the star eat up one character */
+ s++;
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else if(*p == '?') {
+ if(ISPRINT(*s)) {
+ s++;
+ p++;
+ }
+ else if(*s == '\0')
+ return CURL_FNMATCH_NOMATCH;
+ else
+ return CURL_FNMATCH_FAIL; /* cannot deal with other character */
+ }
+ else if(*p == '\0') {
+ if(*s == '\0')
+ return CURL_FNMATCH_MATCH;
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else if(*p == '\\') {
+ state = CURLFNM_LOOP_BACKSLASH;
+ p++;
+ }
+ else if(*p == '[') {
+ unsigned char *pp = p+1; /* cannot handle with pointer to register */
+ if(setcharset(&pp, charset)) {
+ int found = FALSE;
+ if(charset[(unsigned int)*s])
+ found = TRUE;
+ else if(charset[CURLFNM_ALNUM])
+ found = ISALNUM(*s);
+ else if(charset[CURLFNM_ALPHA])
+ found = ISALPHA(*s);
+ else if(charset[CURLFNM_DIGIT])
+ found = ISDIGIT(*s);
+ else if(charset[CURLFNM_XDIGIT])
+ found = ISXDIGIT(*s);
+ else if(charset[CURLFNM_PRINT])
+ found = ISPRINT(*s);
+ else if(charset[CURLFNM_SPACE])
+ found = ISSPACE(*s);
+ else if(charset[CURLFNM_UPPER])
+ found = ISUPPER(*s);
+ else if(charset[CURLFNM_LOWER])
+ found = ISLOWER(*s);
+ else if(charset[CURLFNM_BLANK])
+ found = ISBLANK(*s);
+ else if(charset[CURLFNM_GRAPH])
+ found = ISGRAPH(*s);
+
+ if(charset[CURLFNM_NEGATE])
+ found = !found;
+
+ if(found) {
+ p = pp+1;
+ s++;
+ memset(charset, 0, CURLFNM_CHSET_SIZE);
+ }
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else
+ return CURL_FNMATCH_FAIL;
+ }
+ else {
+ if(*p++ != *s++)
+ return CURL_FNMATCH_NOMATCH;
+ }
+ break;
+ case CURLFNM_LOOP_BACKSLASH:
+ if(ISPRINT(*p)) {
+ if(*p++ == *s++)
+ state = CURLFNM_LOOP_DEFAULT;
+ else
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else
+ return CURL_FNMATCH_FAIL;
+ break;
+ }
+ }
+}
+
+/*
+ * @unittest: 1307
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
+{
+ (void)ptr; /* the argument is specified by the curl_fnmatch_callback
+ prototype, but not used by Curl_fnmatch() */
+ if(!pattern || !string) {
+ return CURL_FNMATCH_FAIL;
+ }
+ return loop((unsigned char *)pattern, (unsigned char *)string);
+}
diff --git a/libs/libcurl/src/curl_fnmatch.h b/libs/libcurl/src/curl_fnmatch.h
new file mode 100644
index 0000000000..6335d03123
--- /dev/null
+++ b/libs/libcurl/src/curl_fnmatch.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_FNMATCH_H
+#define HEADER_CURL_FNMATCH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#define CURL_FNMATCH_MATCH 0
+#define CURL_FNMATCH_NOMATCH 1
+#define CURL_FNMATCH_FAIL 2
+
+/* default pattern matching function
+ * =================================
+ * Implemented with recursive backtracking, if you want to use Curl_fnmatch,
+ * please note that there is not implemented UTF/UNICODE support.
+ *
+ * Implemented features:
+ * '?' notation, does not match UTF characters
+ * '*' can also work with UTF string
+ * [a-zA-Z0-9] enumeration support
+ *
+ * keywords: alnum, digit, xdigit, alpha, print, blank, lower, graph, space
+ * and upper (use as "[[:alnum:]]")
+ */
+int Curl_fnmatch(void *ptr, const char *pattern, const char *string);
+
+#endif /* HEADER_CURL_FNMATCH_H */
diff --git a/libs/libcurl/src/curl_gethostname.c b/libs/libcurl/src/curl_gethostname.c
new file mode 100644
index 0000000000..ded1e6f948
--- /dev/null
+++ b/libs/libcurl/src/curl_gethostname.c
@@ -0,0 +1,100 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 "curl_gethostname.h"
+
+/*
+ * Curl_gethostname() is a wrapper around gethostname() which allows
+ * overriding the host name that the function would normally return.
+ * This capability is used by the test suite to verify exact matching
+ * of NTLM authentication, which exercises libcurl's MD4 and DES code
+ * as well as by the SMTP module when a hostname is not provided.
+ *
+ * For libcurl debug enabled builds host name overriding takes place
+ * when environment variable CURL_GETHOSTNAME is set, using the value
+ * held by the variable to override returned host name.
+ *
+ * Note: The function always returns the un-qualified hostname rather
+ * than being provider dependent.
+ *
+ * For libcurl shared library release builds the test suite preloads
+ * another shared library named libhostname using the LD_PRELOAD
+ * mechanism which intercepts, and might override, the gethostname()
+ * function call. In this case a given platform must support the
+ * LD_PRELOAD mechanism and additionally have environment variable
+ * CURL_GETHOSTNAME set in order to override the returned host name.
+ *
+ * For libcurl static library release builds no overriding takes place.
+ */
+
+int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen) {
+
+#ifndef HAVE_GETHOSTNAME
+
+ /* Allow compilation and return failure when unavailable */
+ (void) name;
+ (void) namelen;
+ return -1;
+
+#else
+ int err;
+ char* dot;
+
+#ifdef DEBUGBUILD
+
+ /* Override host name when environment variable CURL_GETHOSTNAME is set */
+ const char *force_hostname = getenv("CURL_GETHOSTNAME");
+ if(force_hostname) {
+ strncpy(name, force_hostname, namelen);
+ err = 0;
+ }
+ else {
+ name[0] = '\0';
+ err = gethostname(name, namelen);
+ }
+
+#else /* DEBUGBUILD */
+
+ /* The call to system's gethostname() might get intercepted by the
+ libhostname library when libcurl is built as a non-debug shared
+ library when running the test suite. */
+ name[0] = '\0';
+ err = gethostname(name, namelen);
+
+#endif
+
+ name[namelen - 1] = '\0';
+
+ if(err)
+ return err;
+
+ /* Truncate domain, leave only machine name */
+ dot = strchr(name, '.');
+ if(dot)
+ *dot = '\0';
+
+ return 0;
+#endif
+
+}
diff --git a/libs/libcurl/src/curl_gethostname.h b/libs/libcurl/src/curl_gethostname.h
new file mode 100644
index 0000000000..48740f62af
--- /dev/null
+++ b/libs/libcurl/src/curl_gethostname.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_GETHOSTNAME_H
+#define HEADER_CURL_GETHOSTNAME_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+/* Hostname buffer size */
+#define HOSTNAME_MAX 1024
+
+/* This returns the local machine's un-qualified hostname */
+int Curl_gethostname(char *name, GETHOSTNAME_TYPE_ARG2 namelen);
+
+#endif /* HEADER_CURL_GETHOSTNAME_H */
diff --git a/libs/libcurl/src/curl_gssapi.c b/libs/libcurl/src/curl_gssapi.c
new file mode 100644
index 0000000000..fabbe35985
--- /dev/null
+++ b/libs/libcurl/src/curl_gssapi.c
@@ -0,0 +1,69 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2011, 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 HAVE_GSSAPI
+
+#include "curl_gssapi.h"
+#include "sendf.h"
+
+OM_uint32 Curl_gss_init_sec_context(
+ struct SessionHandle *data,
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context,
+ gss_name_t target_name,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags)
+{
+ OM_uint32 req_flags = GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG;
+
+ if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) {
+#ifdef GSS_C_DELEG_POLICY_FLAG
+ req_flags |= GSS_C_DELEG_POLICY_FLAG;
+#else
+ infof(data, "warning: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not "
+ "compiled in\n");
+#endif
+ }
+
+ if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_FLAG)
+ req_flags |= GSS_C_DELEG_FLAG;
+
+ return gss_init_sec_context(minor_status,
+ GSS_C_NO_CREDENTIAL, /* cred_handle */
+ context,
+ target_name,
+ GSS_C_NO_OID, /* mech_type */
+ req_flags,
+ 0, /* time_req */
+ input_chan_bindings,
+ input_token,
+ NULL, /* actual_mech_type */
+ output_token,
+ ret_flags,
+ NULL /* time_rec */);
+}
+
+#endif /* HAVE_GSSAPI */
diff --git a/libs/libcurl/src/curl_gssapi.h b/libs/libcurl/src/curl_gssapi.h
new file mode 100644
index 0000000000..ed33b51a2d
--- /dev/null
+++ b/libs/libcurl/src/curl_gssapi.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_GSSAPI_H
+#define HEADER_CURL_GSSAPI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2011, 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 "urldata.h"
+
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_GSSGNU
+# include <gss.h>
+#elif defined HAVE_GSSMIT
+ /* MIT style */
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_generic.h>
+# include <gssapi/gssapi_krb5.h>
+#else
+ /* Heimdal-style */
+# include <gssapi.h>
+#endif
+
+
+/* Common method for using gss api */
+
+OM_uint32 Curl_gss_init_sec_context(
+ struct SessionHandle *data,
+ OM_uint32 * minor_status,
+ gss_ctx_id_t * context,
+ gss_name_t target_name,
+ gss_channel_bindings_t input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_buffer_t output_token,
+ OM_uint32 * ret_flags);
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* HEADER_CURL_GSSAPI_H */
diff --git a/libs/libcurl/src/curl_hmac.h b/libs/libcurl/src/curl_hmac.h
new file mode 100644
index 0000000000..9b65c8c2a1
--- /dev/null
+++ b/libs/libcurl/src/curl_hmac.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_HMAC_H
+#define HEADER_CURL_HMAC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+typedef void (* HMAC_hinit_func)(void * context);
+typedef void (* HMAC_hupdate_func)(void * context,
+ const unsigned char * data,
+ unsigned int len);
+typedef void (* HMAC_hfinal_func)(unsigned char * result, void * context);
+
+
+/* Per-hash function HMAC parameters. */
+
+typedef struct {
+ HMAC_hinit_func hmac_hinit; /* Initialize context procedure. */
+ HMAC_hupdate_func hmac_hupdate; /* Update context with data. */
+ HMAC_hfinal_func hmac_hfinal; /* Get final result procedure. */
+ unsigned int hmac_ctxtsize; /* Context structure size. */
+ unsigned int hmac_maxkeylen; /* Maximum key length (bytes). */
+ unsigned int hmac_resultlen; /* Result length (bytes). */
+} HMAC_params;
+
+
+/* HMAC computation context. */
+
+typedef struct {
+ const HMAC_params * hmac_hash; /* Hash function definition. */
+ void * hmac_hashctxt1; /* Hash function context 1. */
+ void * hmac_hashctxt2; /* Hash function context 2. */
+} HMAC_context;
+
+
+/* Prototypes. */
+
+HMAC_context * Curl_HMAC_init(const HMAC_params * hashparams,
+ const unsigned char * key,
+ unsigned int keylen);
+int Curl_HMAC_update(HMAC_context * context,
+ const unsigned char * data,
+ unsigned int len);
+int Curl_HMAC_final(HMAC_context * context, unsigned char * result);
+
+#endif
+
+#endif /* HEADER_CURL_HMAC_H */
diff --git a/libs/libcurl/src/curl_ldap.h b/libs/libcurl/src/curl_ldap.h
new file mode 100644
index 0000000000..93fb4b07af
--- /dev/null
+++ b/libs/libcurl/src/curl_ldap.h
@@ -0,0 +1,35 @@
+#ifndef HEADER_CURL_LDAP_H
+#define HEADER_CURL_LDAP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_LDAP
+extern const struct Curl_handler Curl_handler_ldap;
+
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+extern const struct Curl_handler Curl_handler_ldaps;
+#endif
+
+#endif
+#endif /* HEADER_CURL_LDAP_H */
+
diff --git a/libs/libcurl/src/curl_md4.h b/libs/libcurl/src/curl_md4.h
new file mode 100644
index 0000000000..b0be9cf6cf
--- /dev/null
+++ b/libs/libcurl/src/curl_md4.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_MD4_H
+#define HEADER_CURL_MD4_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+/* NSS crypto library does not provide the MD4 hash algorithm, so that we have
+ * a local implementation of it */
+#ifdef USE_NSS
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len);
+#endif /* USE_NSS */
+
+#endif /* HEADER_CURL_MD4_H */
diff --git a/libs/libcurl/src/curl_md5.h b/libs/libcurl/src/curl_md5.h
new file mode 100644
index 0000000000..9c0e0b5eee
--- /dev/null
+++ b/libs/libcurl/src/curl_md5.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_MD5_H
+#define HEADER_CURL_MD5_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+#include "curl_hmac.h"
+
+#define MD5_DIGEST_LEN 16
+
+typedef void (* Curl_MD5_init_func)(void *context);
+typedef void (* Curl_MD5_update_func)(void *context,
+ const unsigned char *data,
+ unsigned int len);
+typedef void (* Curl_MD5_final_func)(unsigned char *result, void *context);
+
+typedef struct {
+ Curl_MD5_init_func md5_init_func; /* Initialize context procedure */
+ Curl_MD5_update_func md5_update_func; /* Update context with data */
+ Curl_MD5_final_func md5_final_func; /* Get final result procedure */
+ unsigned int md5_ctxtsize; /* Context structure size */
+ unsigned int md5_resultlen; /* Result length (bytes) */
+} MD5_params;
+
+typedef struct {
+ const MD5_params *md5_hash; /* Hash function definition */
+ void *md5_hashctx; /* Hash function context */
+} MD5_context;
+
+extern const MD5_params Curl_DIGEST_MD5[1];
+extern const HMAC_params Curl_HMAC_MD5[1];
+
+void Curl_md5it(unsigned char *output,
+ const unsigned char *input);
+
+MD5_context * Curl_MD5_init(const MD5_params *md5params);
+int Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len);
+int Curl_MD5_final(MD5_context *context, unsigned char *result);
+
+#endif
+
+#endif /* HEADER_CURL_MD5_H */
diff --git a/libs/libcurl/src/curl_memory.h b/libs/libcurl/src/curl_memory.h
new file mode 100644
index 0000000000..e3cdc721c4
--- /dev/null
+++ b/libs/libcurl/src/curl_memory.h
@@ -0,0 +1,140 @@
+#ifndef HEADER_CURL_MEMORY_H
+#define HEADER_CURL_MEMORY_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.
+ *
+ ***************************************************************************/
+
+/*
+ * Nasty internal details ahead...
+ *
+ * File curl_memory.h must be included by _all_ *.c source files
+ * that use memory related functions strdup, malloc, calloc, realloc
+ * or free, and given source file is used to build libcurl library.
+ *
+ * There is nearly no exception to above rule. All libcurl source
+ * files in 'lib' subdirectory as well as those living deep inside
+ * 'packages' subdirectories and linked together in order to build
+ * libcurl library shall follow it.
+ *
+ * File lib/strdup.c is an exception, given that it provides a strdup
+ * clone implementation while using malloc. Extra care needed inside
+ * this one. TODO: revisit this paragraph and related code.
+ *
+ * The need for curl_memory.h inclusion is due to libcurl's feature
+ * of allowing library user to provide memory replacement functions,
+ * memory callbacks, at runtime with curl_global_init_mem()
+ *
+ * Any *.c source file used to build libcurl library that does not
+ * include curl_memory.h and uses any memory function of the five
+ * mentioned above will compile without any indication, but it will
+ * trigger weird memory related issues at runtime.
+ *
+ * OTOH some source files from 'lib' subdirectory may additionally be
+ * used directly as source code when using some curlx_ functions by
+ * third party programs that don't even use libcurl at all. When using
+ * these source files in this way it is necessary these are compiled
+ * with CURLX_NO_MEMORY_CALLBACKS defined, in order to ensure that no
+ * attempt of calling libcurl's memory callbacks is done from code
+ * which can not use this machinery.
+ *
+ * Notice that libcurl's 'memory tracking' system works chaining into
+ * the memory callback machinery. This implies that when compiling
+ * 'lib' source files with CURLX_NO_MEMORY_CALLBACKS defined this file
+ * disengages usage of libcurl's 'memory tracking' system, defining
+ * MEMDEBUG_NODEFINES and overriding CURLDEBUG purpose.
+ *
+ * CURLX_NO_MEMORY_CALLBACKS takes precedence over CURLDEBUG. This is
+ * done in order to allow building a 'memory tracking' enabled libcurl
+ * and at the same time allow building programs which do not use it.
+ *
+ * Programs and libraries in 'tests' subdirectories have specific
+ * purposes and needs, and as such each one will use whatever fits
+ * best, depending additionally wether it links with libcurl or not.
+ *
+ * Caveat emptor. Proper curlx_* separation is a work in progress
+ * the same as CURLX_NO_MEMORY_CALLBACKS usage, some adjustments may
+ * still be required. IOW don't use them yet, there are sharp edges.
+ */
+
+#ifdef HEADER_CURL_MEMDEBUG_H
+#error "Header memdebug.h shall not be included before curl_memory.h"
+#endif
+
+#ifndef CURLX_NO_MEMORY_CALLBACKS
+
+#include <curl/curl.h> /* for the callback typedefs */
+
+extern curl_malloc_callback Curl_cmalloc;
+extern curl_free_callback Curl_cfree;
+extern curl_realloc_callback Curl_crealloc;
+extern curl_strdup_callback Curl_cstrdup;
+extern curl_calloc_callback Curl_ccalloc;
+#if defined(WIN32) && defined(UNICODE)
+extern curl_wcsdup_callback Curl_cwcsdup;
+#endif
+
+#ifndef CURLDEBUG
+
+/*
+ * libcurl's 'memory tracking' system defines strdup, malloc, calloc,
+ * realloc and free, along with others, in memdebug.h in a different
+ * way although still using memory callbacks forward declared above.
+ * When using the 'memory tracking' system (CURLDEBUG defined) we do
+ * not define here the five memory functions given that definitions
+ * from memdebug.h are the ones that shall be used.
+ */
+
+#undef strdup
+#define strdup(ptr) Curl_cstrdup(ptr)
+#undef malloc
+#define malloc(size) Curl_cmalloc(size)
+#undef calloc
+#define calloc(nbelem,size) Curl_ccalloc(nbelem, size)
+#undef realloc
+#define realloc(ptr,size) Curl_crealloc(ptr, size)
+#undef free
+#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
+# define _tcsdup(ptr) Curl_cwcsdup(ptr)
+# else
+# undef _tcsdup
+# define _tcsdup(ptr) Curl_cstrdup(ptr)
+# endif
+#endif
+
+#endif /* CURLDEBUG */
+
+#else /* CURLX_NO_MEMORY_CALLBACKS */
+
+#ifndef MEMDEBUG_NODEFINES
+#define MEMDEBUG_NODEFINES
+#endif
+
+#endif /* CURLX_NO_MEMORY_CALLBACKS */
+
+#endif /* HEADER_CURL_MEMORY_H */
diff --git a/libs/libcurl/src/curl_memrchr.c b/libs/libcurl/src/curl_memrchr.c
new file mode 100644
index 0000000000..a71c2bb4ae
--- /dev/null
+++ b/libs/libcurl/src/curl_memrchr.c
@@ -0,0 +1,62 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "curl_memrchr.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"
+
+#ifndef HAVE_MEMRCHR
+
+/*
+ * Curl_memrchr()
+ *
+ * Our memrchr() function clone for systems which lack this function. The
+ * memrchr() function is like the memchr() function, except that it searches
+ * backwards from the end of the n bytes pointed to by s instead of forward
+ * from the beginning.
+ */
+
+void *
+Curl_memrchr(const void *s, int c, size_t n)
+{
+ const unsigned char *p = s;
+ const unsigned char *q = s;
+
+ p += n - 1;
+
+ while(p >= q) {
+ if(*p == (unsigned char)c)
+ return (void *)p;
+ p--;
+ }
+
+ return NULL;
+}
+
+#endif /* HAVE_MEMRCHR */
diff --git a/libs/libcurl/src/curl_memrchr.h b/libs/libcurl/src/curl_memrchr.h
new file mode 100644
index 0000000000..324c73a7b8
--- /dev/null
+++ b/libs/libcurl/src/curl_memrchr.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_MEMRCHR_H
+#define HEADER_CURL_MEMRCHR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 HAVE_MEMRCHR
+
+#ifdef HAVE_STRING_H
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+
+#else /* HAVE_MEMRCHR */
+
+void *Curl_memrchr(const void *s, int c, size_t n);
+
+#define memrchr(x,y,z) Curl_memrchr((x),(y),(z))
+
+#endif /* HAVE_MEMRCHR */
+
+#endif /* HEADER_CURL_MEMRCHR_H */
diff --git a/libs/libcurl/src/curl_multibyte.c b/libs/libcurl/src/curl_multibyte.c
new file mode 100644
index 0000000000..6c02239eb0
--- /dev/null
+++ b/libs/libcurl/src/curl_multibyte.c
@@ -0,0 +1,82 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(USE_WIN32_IDN) || (defined(USE_WINDOWS_SSPI) && defined(UNICODE))
+
+ /*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+#include "curl_multibyte.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"
+
+wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8)
+{
+ wchar_t *str_w = NULL;
+
+ if(str_utf8) {
+ int str_w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS,
+ str_utf8, -1, NULL, 0);
+ if(str_w_len > 0) {
+ str_w = malloc(str_w_len * sizeof(wchar_t));
+ if(str_w) {
+ if(MultiByteToWideChar(CP_UTF8, 0, str_utf8, -1, str_w,
+ str_w_len) == 0) {
+ Curl_safefree(str_w);
+ }
+ }
+ }
+ }
+
+ return str_w;
+}
+
+char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w)
+{
+ char *str_utf8 = NULL;
+
+ if(str_w) {
+ int str_utf8_len = WideCharToMultiByte(CP_UTF8, 0, str_w, -1, NULL,
+ 0, NULL, NULL);
+ if(str_utf8_len > 0) {
+ str_utf8 = malloc(str_utf8_len * sizeof(wchar_t));
+ if(str_utf8) {
+ if(WideCharToMultiByte(CP_UTF8, 0, str_w, -1, str_utf8, str_utf8_len,
+ NULL, FALSE) == 0) {
+ Curl_safefree(str_utf8);
+ }
+ }
+ }
+ }
+
+ return str_utf8;
+}
+
+#endif /* USE_WIN32_IDN || (USE_WINDOWS_SSPI && UNICODE) */
diff --git a/libs/libcurl/src/curl_multibyte.h b/libs/libcurl/src/curl_multibyte.h
new file mode 100644
index 0000000000..7ee5eae126
--- /dev/null
+++ b/libs/libcurl/src/curl_multibyte.h
@@ -0,0 +1,90 @@
+#ifndef HEADER_CURL_MULTIBYTE_H
+#define HEADER_CURL_MULTIBYTE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(USE_WIN32_IDN) || (defined(USE_WINDOWS_SSPI) && defined(UNICODE))
+
+ /*
+ * MultiByte conversions using Windows kernel32 library.
+ */
+
+wchar_t *Curl_convert_UTF8_to_wchar(const char *str_utf8);
+char *Curl_convert_wchar_to_UTF8(const wchar_t *str_w);
+
+#endif /* USE_WIN32_IDN || (USE_WINDOWS_SSPI && UNICODE) */
+
+
+#if defined(USE_WIN32_IDN) || defined(USE_WINDOWS_SSPI)
+
+/*
+ * Macros Curl_convert_UTF8_to_tchar(), Curl_convert_tchar_to_UTF8()
+ * and Curl_unicodefree() main purpose is to minimize the number of
+ * preprocessor conditional directives needed by code using these
+ * to differentiate UNICODE from non-UNICODE builds.
+ *
+ * When building with UNICODE defined, this two macros
+ * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
+ * return a pointer to a newly allocated memory area holding result.
+ * When the result is no longer needed, allocated memory is intended
+ * to be free'ed with Curl_unicodefree().
+ *
+ * When building without UNICODE defined, this macros
+ * Curl_convert_UTF8_to_tchar() and Curl_convert_tchar_to_UTF8()
+ * return the pointer received as argument. Curl_unicodefree() does
+ * no actual free'ing of this pointer it is simply set to NULL.
+ */
+
+#ifdef UNICODE
+
+#define Curl_convert_UTF8_to_tchar(ptr) Curl_convert_UTF8_to_wchar((ptr))
+#define Curl_convert_tchar_to_UTF8(ptr) Curl_convert_wchar_to_UTF8((ptr))
+#define Curl_unicodefree(ptr) \
+ do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE
+
+typedef union {
+ unsigned short *tchar_ptr;
+ const unsigned short *const_tchar_ptr;
+ unsigned short *tbyte_ptr;
+ const unsigned short *const_tbyte_ptr;
+} xcharp_u;
+
+#else
+
+#define Curl_convert_UTF8_to_tchar(ptr) (ptr)
+#define Curl_convert_tchar_to_UTF8(ptr) (ptr)
+#define Curl_unicodefree(ptr) \
+ do {(ptr) = NULL;} WHILE_FALSE
+
+typedef union {
+ char *tchar_ptr;
+ const char *const_tchar_ptr;
+ unsigned char *tbyte_ptr;
+ const unsigned char *const_tbyte_ptr;
+} xcharp_u;
+
+#endif /* UNICODE */
+
+#endif /* USE_WIN32_IDN || USE_WINDOWS_SSPI */
+
+#endif /* HEADER_CURL_MULTIBYTE_H */
diff --git a/libs/libcurl/src/curl_ntlm.c b/libs/libcurl/src/curl_ntlm.c
new file mode 100644
index 0000000000..4d126a573e
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm.c
@@ -0,0 +1,244 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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_NTLM
+
+/*
+ * NTLM details:
+ *
+ * http://davenport.sourceforge.net/ntlm.html
+ * http://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "curl_ntlm.h"
+#include "curl_ntlm_msgs.h"
+#include "curl_ntlm_wb.h"
+#include "url.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#if defined(USE_NSS)
+#include "nssg.h"
+#elif defined(USE_WINDOWS_SSPI)
+#include "curl_sspi.h"
+#endif
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+CURLcode Curl_input_ntlm(struct connectdata *conn,
+ bool proxy, /* if proxy or not */
+ const char *header) /* rest of the www-authenticate:
+ header */
+{
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ CURLcode result = CURLE_OK;
+
+#ifdef USE_NSS
+ result = Curl_nss_force_init(conn->data);
+ if(result)
+ return result;
+#endif
+
+ ntlm = proxy ? &conn->proxyntlm : &conn->ntlm;
+
+ /* skip initial whitespaces */
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(checkprefix("NTLM", header)) {
+ header += strlen("NTLM");
+
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(*header) {
+ result = Curl_ntlm_decode_type2_message(conn->data, header, ntlm);
+ if(CURLE_OK != result)
+ return result;
+
+ ntlm->state = NTLMSTATE_TYPE2; /* We got a type-2 message */
+ }
+ else {
+ if(ntlm->state == NTLMSTATE_TYPE3) {
+ infof(conn->data, "NTLM handshake rejected\n");
+ Curl_http_ntlm_cleanup(conn);
+ ntlm->state = NTLMSTATE_NONE;
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ else if(ntlm->state >= NTLMSTATE_TYPE1) {
+ infof(conn->data, "NTLM handshake failure (internal error)\n");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ ntlm->state = NTLMSTATE_TYPE1; /* We should send away a type-1 */
+ }
+ }
+
+ return result;
+}
+
+/*
+ * This is for creating ntlm header output
+ */
+CURLcode Curl_output_ntlm(struct connectdata *conn,
+ bool proxy)
+{
+ char *base64 = NULL;
+ size_t len = 0;
+ CURLcode error;
+
+ /* point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+
+ /* point to the name and password for this */
+ const char *userp;
+ const char *passwdp;
+
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ struct auth *authp;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->data);
+
+#ifdef USE_NSS
+ if(CURLE_OK != Curl_nss_force_init(conn->data))
+ return CURLE_OUT_OF_MEMORY;
+#endif
+
+ if(proxy) {
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->proxyuser;
+ passwdp = conn->proxypasswd;
+ ntlm = &conn->proxyntlm;
+ authp = &conn->data->state.authproxy;
+ }
+ else {
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ ntlm = &conn->ntlm;
+ authp = &conn->data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp = "";
+
+ if(!passwdp)
+ passwdp = "";
+
+#ifdef USE_WINDOWS_SSPI
+ if(s_hSecDll == NULL) {
+ /* not thread safe and leaks - use curl_global_init() to avoid */
+ CURLcode err = Curl_sspi_global_init();
+ if(s_hSecDll == NULL)
+ return err;
+ }
+#endif
+
+ switch(ntlm->state) {
+ case NTLMSTATE_TYPE1:
+ default: /* for the weird cases we (re)start here */
+ /* Create a type-1 message */
+ error = Curl_ntlm_create_type1_message(userp, passwdp, ntlm, &base64,
+ &len);
+ if(error)
+ return error;
+
+ if(base64) {
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+ DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ }
+ break;
+
+ case NTLMSTATE_TYPE2:
+ /* We already received the type-2 message, create a type-3 message */
+ error = Curl_ntlm_create_type3_message(conn->data, userp, passwdp,
+ ntlm, &base64, &len);
+ if(error)
+ return error;
+
+ if(base64) {
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: NTLM %s\r\n",
+ proxy ? "Proxy-" : "",
+ base64);
+ free(base64);
+ if(!*allocuserpwd)
+ return CURLE_OUT_OF_MEMORY;
+ DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+
+ ntlm->state = NTLMSTATE_TYPE3; /* we send a type-3 */
+ authp->done = TRUE;
+ }
+ break;
+
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ Curl_safefree(*allocuserpwd);
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_http_ntlm_cleanup(struct connectdata *conn)
+{
+#ifdef USE_WINDOWS_SSPI
+ Curl_ntlm_sspi_cleanup(&conn->ntlm);
+ Curl_ntlm_sspi_cleanup(&conn->proxyntlm);
+#elif defined(NTLM_WB_ENABLED)
+ Curl_ntlm_wb_cleanup(conn);
+#else
+ (void)conn;
+#endif
+}
+
+#endif /* USE_NTLM */
diff --git a/libs/libcurl/src/curl_ntlm.h b/libs/libcurl/src/curl_ntlm.h
new file mode 100644
index 0000000000..21a9e9e47b
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm.h
@@ -0,0 +1,44 @@
+#ifndef HEADER_CURL_NTLM_H
+#define HEADER_CURL_NTLM_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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_NTLM
+
+/* this is for ntlm header input */
+CURLcode Curl_input_ntlm(struct connectdata *conn, bool proxy,
+ const char *header);
+
+/* this is for creating ntlm header output */
+CURLcode Curl_output_ntlm(struct connectdata *conn, bool proxy);
+
+void Curl_http_ntlm_cleanup(struct connectdata *conn);
+
+#else
+
+#define Curl_http_ntlm_cleanup(a) Curl_nop_stmt
+
+#endif
+
+#endif /* HEADER_CURL_NTLM_H */
diff --git a/libs/libcurl/src/curl_ntlm_core.c b/libs/libcurl/src/curl_ntlm_core.c
new file mode 100644
index 0000000000..79aeb08b3f
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_core.c
@@ -0,0 +1,436 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
+
+/*
+ * NTLM details:
+ *
+ * http://davenport.sourceforge.net/ntlm.html
+ * http://www.innovation.ch/java/ntlm.html
+ */
+
+#ifdef USE_SSLEAY
+
+# ifdef USE_OPENSSL
+# include <openssl/des.h>
+# ifndef OPENSSL_NO_MD4
+# include <openssl/md4.h>
+# endif
+# include <openssl/md5.h>
+# include <openssl/ssl.h>
+# include <openssl/rand.h>
+# else
+# include <des.h>
+# ifndef OPENSSL_NO_MD4
+# include <md4.h>
+# endif
+# include <md5.h>
+# include <ssl.h>
+# include <rand.h>
+# endif
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+# define DES_key_schedule des_key_schedule
+# define DES_cblock des_cblock
+# define DES_set_odd_parity des_set_odd_parity
+# define DES_set_key des_set_key
+# define DES_ecb_encrypt des_ecb_encrypt
+# define DESKEY(x) x
+# define DESKEYARG(x) x
+# else
+# define DESKEYARG(x) *x
+# define DESKEY(x) &x
+# endif
+
+#elif defined(USE_GNUTLS_NETTLE)
+
+# include <nettle/des.h>
+# include <nettle/md4.h>
+
+#elif defined(USE_GNUTLS)
+
+# include <gcrypt.h>
+# define MD5_DIGEST_LENGTH 16
+# define MD4_DIGEST_LENGTH 16
+
+#elif defined(USE_NSS)
+
+# include <nss.h>
+# include <pk11pub.h>
+# include <hasht.h>
+# include "curl_md4.h"
+# define MD5_DIGEST_LENGTH MD5_LENGTH
+
+#elif defined(USE_DARWINSSL)
+
+# include <CommonCrypto/CommonCryptor.h>
+# include <CommonCrypto/CommonDigest.h>
+
+#else
+# error "Can't compile NTLM support without a crypto library."
+#endif
+
+#include "urldata.h"
+#include "non-ascii.h"
+#include "rawstr.h"
+#include "curl_memory.h"
+#include "curl_ntlm_core.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef USE_SSLEAY
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key. The
+ * key schedule ks is also set.
+ */
+static void setup_des_key(const unsigned char *key_56,
+ DES_key_schedule DESKEYARG(ks))
+{
+ DES_cblock key;
+
+ key[0] = key_56[0];
+ key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+ key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+ key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+ key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+ key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+ key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+ key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+
+ DES_set_odd_parity(&key);
+ DES_set_key(&key, ks);
+}
+
+#else /* defined(USE_SSLEAY) */
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key. Used by GnuTLS and NSS.
+ */
+static void extend_key_56_to_64(const unsigned char *key_56, char *key)
+{
+ key[0] = key_56[0];
+ key[1] = (unsigned char)(((key_56[0] << 7) & 0xFF) | (key_56[1] >> 1));
+ key[2] = (unsigned char)(((key_56[1] << 6) & 0xFF) | (key_56[2] >> 2));
+ key[3] = (unsigned char)(((key_56[2] << 5) & 0xFF) | (key_56[3] >> 3));
+ key[4] = (unsigned char)(((key_56[3] << 4) & 0xFF) | (key_56[4] >> 4));
+ key[5] = (unsigned char)(((key_56[4] << 3) & 0xFF) | (key_56[5] >> 5));
+ key[6] = (unsigned char)(((key_56[5] << 2) & 0xFF) | (key_56[6] >> 6));
+ key[7] = (unsigned char) ((key_56[6] << 1) & 0xFF);
+}
+
+#if defined(USE_GNUTLS_NETTLE)
+
+static void setup_des_key(const unsigned char *key_56,
+ struct des_ctx *des)
+{
+ char key[8];
+ extend_key_56_to_64(key_56, key);
+ des_set_key(des, (const uint8_t*)key);
+}
+
+#elif defined(USE_GNUTLS)
+
+/*
+ * Turns a 56 bit key into the 64 bit, odd parity key and sets the key.
+ */
+static void setup_des_key(const unsigned char *key_56,
+ gcry_cipher_hd_t *des)
+{
+ char key[8];
+ extend_key_56_to_64(key_56, key);
+ gcry_cipher_setkey(*des, key, 8);
+}
+
+#elif defined(USE_NSS)
+
+/*
+ * Expands a 56 bit key KEY_56 to 64 bit and encrypts 64 bit of data, using
+ * the expanded key. The caller is responsible for giving 64 bit of valid
+ * data is IN and (at least) 64 bit large buffer as OUT.
+ */
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ const CK_MECHANISM_TYPE mech = CKM_DES_ECB; /* DES cipher in ECB mode */
+ PK11SlotInfo *slot = NULL;
+ char key[8]; /* expanded 64 bit key */
+ SECItem key_item;
+ PK11SymKey *symkey = NULL;
+ SECItem *param = NULL;
+ PK11Context *ctx = NULL;
+ int out_len; /* not used, required by NSS */
+ bool rv = FALSE;
+
+ /* use internal slot for DES encryption (requires NSS to be initialized) */
+ slot = PK11_GetInternalKeySlot();
+ if(!slot)
+ return FALSE;
+
+ /* expand the 56 bit key to 64 bit and wrap by NSS */
+ extend_key_56_to_64(key_56, key);
+ key_item.data = (unsigned char *)key;
+ key_item.len = /* hard-wired */ 8;
+ symkey = PK11_ImportSymKey(slot, mech, PK11_OriginUnwrap, CKA_ENCRYPT,
+ &key_item, NULL);
+ if(!symkey)
+ goto fail;
+
+ /* create DES encryption context */
+ param = PK11_ParamFromIV(mech, /* no IV in ECB mode */ NULL);
+ if(!param)
+ goto fail;
+ ctx = PK11_CreateContextBySymKey(mech, CKA_ENCRYPT, symkey, param);
+ if(!ctx)
+ goto fail;
+
+ /* perform the encryption */
+ if(SECSuccess == PK11_CipherOp(ctx, out, &out_len, /* outbuflen */ 8,
+ (unsigned char *)in, /* inbuflen */ 8)
+ && SECSuccess == PK11_Finalize(ctx))
+ rv = /* all OK */ TRUE;
+
+fail:
+ /* cleanup */
+ if(ctx)
+ PK11_DestroyContext(ctx, PR_TRUE);
+ if(symkey)
+ PK11_FreeSymKey(symkey);
+ if(param)
+ SECITEM_FreeItem(param, PR_TRUE);
+ PK11_FreeSlot(slot);
+ return rv;
+}
+
+#elif defined(USE_DARWINSSL)
+
+static bool encrypt_des(const unsigned char *in, unsigned char *out,
+ const unsigned char *key_56)
+{
+ char key[8];
+ size_t out_len;
+ CCCryptorStatus err;
+
+ extend_key_56_to_64(key_56, key);
+ err = CCCrypt(kCCEncrypt, kCCAlgorithmDES, kCCOptionECBMode, key,
+ kCCKeySizeDES, NULL, in, 8 /* inbuflen */, out,
+ 8 /* outbuflen */, &out_len);
+ return err == kCCSuccess;
+}
+
+#endif /* defined(USE_DARWINSSL) */
+
+#endif /* defined(USE_SSLEAY) */
+
+ /*
+ * takes a 21 byte array and treats it as 3 56-bit DES keys. The
+ * 8 byte plaintext is encrypted with each key and the resulting 24
+ * bytes are stored in the results array.
+ */
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+ const unsigned char *plaintext,
+ unsigned char *results)
+{
+#ifdef USE_SSLEAY
+ DES_key_schedule ks;
+
+ setup_des_key(keys, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) results,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys + 7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 8),
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(keys + 14, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock*) plaintext, (DES_cblock*) (results + 16),
+ DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct des_ctx des;
+ setup_des_key(keys, &des);
+ des_encrypt(&des, 8, results, plaintext);
+ setup_des_key(keys + 7, &des);
+ des_encrypt(&des, 8, results + 8, plaintext);
+ setup_des_key(keys + 14, &des);
+ des_encrypt(&des, 8, results + 16, plaintext);
+#elif defined(USE_GNUTLS)
+ gcry_cipher_hd_t des;
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys, &des);
+ gcry_cipher_encrypt(des, results, 8, plaintext, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys + 7, &des);
+ gcry_cipher_encrypt(des, results + 8, 8, plaintext, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(keys + 14, &des);
+ gcry_cipher_encrypt(des, results + 16, 8, plaintext, 8);
+ gcry_cipher_close(des);
+#elif defined(USE_NSS) || defined(USE_DARWINSSL)
+ encrypt_des(plaintext, results, keys);
+ encrypt_des(plaintext, results + 8, keys + 7);
+ encrypt_des(plaintext, results + 16, keys + 14);
+#endif
+}
+
+/*
+ * Set up lanmanager hashed password
+ */
+void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data,
+ const char *password,
+ unsigned char *lmbuffer /* 21 bytes */)
+{
+ CURLcode res;
+ unsigned char pw[14];
+ static const unsigned char magic[] = {
+ 0x4B, 0x47, 0x53, 0x21, 0x40, 0x23, 0x24, 0x25 /* i.e. KGS!@#$% */
+ };
+ size_t len = CURLMIN(strlen(password), 14);
+
+ Curl_strntoupper((char *)pw, password, len);
+ memset(&pw[len], 0, 14 - len);
+
+ /*
+ * The LanManager hashed password needs to be created using the
+ * password in the network encoding not the host encoding.
+ */
+ res = Curl_convert_to_network(data, (char *)pw, 14);
+ if(res)
+ return;
+
+ {
+ /* Create LanManager hashed password. */
+
+#ifdef USE_SSLEAY
+ DES_key_schedule ks;
+
+ setup_des_key(pw, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)lmbuffer,
+ DESKEY(ks), DES_ENCRYPT);
+
+ setup_des_key(pw + 7, DESKEY(ks));
+ DES_ecb_encrypt((DES_cblock *)magic, (DES_cblock *)(lmbuffer + 8),
+ DESKEY(ks), DES_ENCRYPT);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct des_ctx des;
+ setup_des_key(pw, &des);
+ des_encrypt(&des, 8, lmbuffer, magic);
+ setup_des_key(pw + 7, &des);
+ des_encrypt(&des, 8, lmbuffer + 8, magic);
+#elif defined(USE_GNUTLS)
+ gcry_cipher_hd_t des;
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(pw, &des);
+ gcry_cipher_encrypt(des, lmbuffer, 8, magic, 8);
+ gcry_cipher_close(des);
+
+ gcry_cipher_open(&des, GCRY_CIPHER_DES, GCRY_CIPHER_MODE_ECB, 0);
+ setup_des_key(pw + 7, &des);
+ gcry_cipher_encrypt(des, lmbuffer + 8, 8, magic, 8);
+ gcry_cipher_close(des);
+#elif defined(USE_NSS) || defined(USE_DARWINSSL)
+ encrypt_des(magic, lmbuffer, pw);
+ encrypt_des(magic, lmbuffer + 8, pw + 7);
+#endif
+
+ memset(lmbuffer + 16, 0, 21 - 16);
+ }
+}
+
+#if USE_NTRESPONSES
+static void ascii_to_unicode_le(unsigned char *dest, const char *src,
+ size_t srclen)
+{
+ size_t i;
+ for(i = 0; i < srclen; i++) {
+ dest[2 * i] = (unsigned char)src[i];
+ dest[2 * i + 1] = '\0';
+ }
+}
+
+/*
+ * Set up nt hashed passwords
+ */
+CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data,
+ const char *password,
+ unsigned char *ntbuffer /* 21 bytes */)
+{
+ size_t len = strlen(password);
+ unsigned char *pw = malloc(len * 2);
+ CURLcode result;
+ if(!pw)
+ return CURLE_OUT_OF_MEMORY;
+
+ ascii_to_unicode_le(pw, password, len);
+
+ /*
+ * The NT hashed password needs to be created using the password in the
+ * network encoding not the host encoding.
+ */
+ result = Curl_convert_to_network(data, (char *)pw, len * 2);
+ if(result)
+ return result;
+
+ {
+ /* Create NT hashed password. */
+#ifdef USE_SSLEAY
+ MD4_CTX MD4pw;
+ MD4_Init(&MD4pw);
+ MD4_Update(&MD4pw, pw, 2 * len);
+ MD4_Final(ntbuffer, &MD4pw);
+#elif defined(USE_GNUTLS_NETTLE)
+ struct md4_ctx MD4pw;
+ md4_init(&MD4pw);
+ md4_update(&MD4pw, (unsigned int)(2 * len), pw);
+ md4_digest(&MD4pw, MD4_DIGEST_SIZE, ntbuffer);
+#elif defined(USE_GNUTLS)
+ gcry_md_hd_t MD4pw;
+ gcry_md_open(&MD4pw, GCRY_MD_MD4, 0);
+ gcry_md_write(MD4pw, pw, 2 * len);
+ memcpy (ntbuffer, gcry_md_read (MD4pw, 0), MD4_DIGEST_LENGTH);
+ gcry_md_close(MD4pw);
+#elif defined(USE_NSS)
+ Curl_md4it(ntbuffer, pw, 2 * len);
+#elif defined(USE_DARWINSSL)
+ (void)CC_MD4(pw, (CC_LONG)(2 * len), ntbuffer);
+#endif
+
+ memset(ntbuffer + 16, 0, 21 - 16);
+ }
+
+ free(pw);
+
+ return CURLE_OK;
+}
+#endif /* USE_NTRESPONSES */
+
+#endif /* USE_NTLM && !USE_WINDOWS_SSPI */
diff --git a/libs/libcurl/src/curl_ntlm_core.h b/libs/libcurl/src/curl_ntlm_core.h
new file mode 100644
index 0000000000..9aa126bb26
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_core.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_NTLM_CORE_H
+#define HEADER_CURL_NTLM_CORE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+#if defined(USE_NTLM) && !defined(USE_WINDOWS_SSPI)
+
+#ifdef USE_SSLEAY
+# if !defined(OPENSSL_VERSION_NUMBER) && \
+ !defined(HEADER_SSL_H) && !defined(HEADER_MD5_H)
+# error "curl_ntlm_core.h shall not be included before OpenSSL headers."
+# endif
+# ifdef OPENSSL_NO_MD4
+# define USE_NTRESPONSES 0
+# define USE_NTLM2SESSION 0
+# endif
+#endif
+
+/*
+ * Define USE_NTRESPONSES to 1 in order to make the type-3 message include
+ * the NT response message. Define USE_NTLM2SESSION to 1 in order to make
+ * the type-3 message include the NTLM2Session response message, requires
+ * USE_NTRESPONSES defined to 1.
+ */
+
+#ifndef USE_NTRESPONSES
+# define USE_NTRESPONSES 1
+# define USE_NTLM2SESSION 1
+#endif
+
+void Curl_ntlm_core_lm_resp(const unsigned char *keys,
+ const unsigned char *plaintext,
+ unsigned char *results);
+
+void Curl_ntlm_core_mk_lm_hash(struct SessionHandle *data,
+ const char *password,
+ unsigned char *lmbuffer /* 21 bytes */);
+
+#if USE_NTRESPONSES
+CURLcode Curl_ntlm_core_mk_nt_hash(struct SessionHandle *data,
+ const char *password,
+ unsigned char *ntbuffer /* 21 bytes */);
+#endif
+
+#endif /* USE_NTLM && !USE_WINDOWS_SSPI */
+
+#endif /* HEADER_CURL_NTLM_CORE_H */
diff --git a/libs/libcurl/src/curl_ntlm_msgs.c b/libs/libcurl/src/curl_ntlm_msgs.c
new file mode 100644
index 0000000000..125ce6e496
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_msgs.c
@@ -0,0 +1,920 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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_NTLM
+
+/*
+ * NTLM details:
+ *
+ * http://davenport.sourceforge.net/ntlm.html
+ * http://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#include "urldata.h"
+#include "non-ascii.h"
+#include "sendf.h"
+#include "curl_base64.h"
+#include "curl_ntlm_core.h"
+#include "curl_gethostname.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+#include "curl_memory.h"
+
+#ifdef USE_WINDOWS_SSPI
+# include "curl_sspi.h"
+#endif
+
+#include "sslgen.h"
+
+#define BUILDING_CURL_NTLM_MSGS_C
+#include "curl_ntlm_msgs.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* "NTLMSSP" signature is always in ASCII regardless of the platform */
+#define NTLMSSP_SIGNATURE "\x4e\x54\x4c\x4d\x53\x53\x50"
+
+#define SHORTPAIR(x) ((x) & 0xff), (((x) >> 8) & 0xff)
+#define LONGQUARTET(x) ((x) & 0xff), (((x) >> 8) & 0xff), \
+ (((x) >> 16) & 0xff), (((x) >> 24) & 0xff)
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+static void ntlm_print_flags(FILE *handle, unsigned long flags)
+{
+ if(flags & NTLMFLAG_NEGOTIATE_UNICODE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_UNICODE ");
+ if(flags & NTLMFLAG_NEGOTIATE_OEM)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_OEM ");
+ if(flags & NTLMFLAG_REQUEST_TARGET)
+ fprintf(handle, "NTLMFLAG_REQUEST_TARGET ");
+ if(flags & (1<<3))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_3 ");
+ if(flags & NTLMFLAG_NEGOTIATE_SIGN)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_SIGN ");
+ if(flags & NTLMFLAG_NEGOTIATE_SEAL)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_SEAL ");
+ if(flags & NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE ");
+ if(flags & NTLMFLAG_NEGOTIATE_LM_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_LM_KEY ");
+ if(flags & NTLMFLAG_NEGOTIATE_NETWARE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NETWARE ");
+ if(flags & NTLMFLAG_NEGOTIATE_NTLM_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM_KEY ");
+ if(flags & (1<<10))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_10 ");
+ if(flags & NTLMFLAG_NEGOTIATE_ANONYMOUS)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_ANONYMOUS ");
+ if(flags & NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED ");
+ if(flags & NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED ");
+ if(flags & NTLMFLAG_NEGOTIATE_LOCAL_CALL)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_LOCAL_CALL ");
+ if(flags & NTLMFLAG_NEGOTIATE_ALWAYS_SIGN)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_ALWAYS_SIGN ");
+ if(flags & NTLMFLAG_TARGET_TYPE_DOMAIN)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_DOMAIN ");
+ if(flags & NTLMFLAG_TARGET_TYPE_SERVER)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_SERVER ");
+ if(flags & NTLMFLAG_TARGET_TYPE_SHARE)
+ fprintf(handle, "NTLMFLAG_TARGET_TYPE_SHARE ");
+ if(flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_NTLM2_KEY ");
+ if(flags & NTLMFLAG_REQUEST_INIT_RESPONSE)
+ fprintf(handle, "NTLMFLAG_REQUEST_INIT_RESPONSE ");
+ if(flags & NTLMFLAG_REQUEST_ACCEPT_RESPONSE)
+ fprintf(handle, "NTLMFLAG_REQUEST_ACCEPT_RESPONSE ");
+ if(flags & NTLMFLAG_REQUEST_NONNT_SESSION_KEY)
+ fprintf(handle, "NTLMFLAG_REQUEST_NONNT_SESSION_KEY ");
+ if(flags & NTLMFLAG_NEGOTIATE_TARGET_INFO)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_TARGET_INFO ");
+ if(flags & (1<<24))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_24 ");
+ if(flags & (1<<25))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_25 ");
+ if(flags & (1<<26))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_26 ");
+ if(flags & (1<<27))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_27 ");
+ if(flags & (1<<28))
+ fprintf(handle, "NTLMFLAG_UNKNOWN_28 ");
+ if(flags & NTLMFLAG_NEGOTIATE_128)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_128 ");
+ if(flags & NTLMFLAG_NEGOTIATE_KEY_EXCHANGE)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_KEY_EXCHANGE ");
+ if(flags & NTLMFLAG_NEGOTIATE_56)
+ fprintf(handle, "NTLMFLAG_NEGOTIATE_56 ");
+}
+
+static void ntlm_print_hex(FILE *handle, const char *buf, size_t len)
+{
+ const char *p = buf;
+ (void)handle;
+ fprintf(stderr, "0x");
+ while(len-- > 0)
+ fprintf(stderr, "%02.2x", (unsigned int)*p++);
+}
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+#ifndef USE_WINDOWS_SSPI
+/*
+ * This function converts from the little endian format used in the
+ * incoming package to whatever endian format we're using natively.
+ * Argument is a pointer to a 4 byte buffer.
+ */
+static unsigned int readint_le(unsigned char *buf)
+{
+ return ((unsigned int)buf[0]) | ((unsigned int)buf[1] << 8) |
+ ((unsigned int)buf[2] << 16) | ((unsigned int)buf[3] << 24);
+}
+#endif
+
+/*
+ NTLM message structure notes:
+
+ A 'short' is a 'network short', a little-endian 16-bit unsigned value.
+
+ A 'long' is a 'network long', a little-endian, 32-bit unsigned value.
+
+ A 'security buffer' represents a triplet used to point to a buffer,
+ consisting of two shorts and one long:
+
+ 1. A 'short' containing the length of the buffer content in bytes.
+ 2. A 'short' containing the allocated space for the buffer in bytes.
+ 3. A 'long' containing the offset to the start of the buffer in bytes,
+ from the beginning of the NTLM message.
+*/
+
+/*
+ * Curl_ntlm_decode_type2_message()
+ *
+ * This is used to decode a ntlm type-2 message received from a HTTP or SASL
+ * based (such as SMTP, POP3 or IMAP) server. The message is first decoded
+ * from a base64 string into a raw ntlm message and checked for validity
+ * before the appropriate data for creating a type-3 message is written to
+ * the given ntlm data structure.
+ *
+ * Parameters:
+ *
+ * data [in] - Pointer to session handle.
+ * header [in] - Pointer to the input buffer.
+ * ntlm [in] - Pointer to ntlm data struct being used and modified.
+ *
+ * Returns CURLE_OK on success.
+ */
+CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
+ const char* header,
+ struct ntlmdata* ntlm)
+{
+#ifndef USE_WINDOWS_SSPI
+ static const char type2_marker[] = { 0x02, 0x00, 0x00, 0x00 };
+#endif
+
+ /* NTLM type-2 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x02000000)
+ 12 Target Name security buffer
+ 20 Flags long
+ 24 Challenge 8 bytes
+ (32) Context 8 bytes (two consecutive longs) (*)
+ (40) Target Information security buffer (*)
+ (48) OS Version Structure 8 bytes (*)
+ 32 (48) (56) Start of data block (*)
+ (*) -> Optional
+ */
+
+ size_t size = 0;
+ unsigned char *buffer = NULL;
+ CURLcode error;
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS) || defined(USE_WINDOWS_SSPI)
+ (void)data;
+#endif
+
+ error = Curl_base64_decode(header, &buffer, &size);
+ if(error)
+ return error;
+
+ if(!buffer) {
+ infof(data, "NTLM handshake failure (unhandled condition)\n");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+#ifdef USE_WINDOWS_SSPI
+ ntlm->type_2 = malloc(size + 1);
+ if(ntlm->type_2 == NULL) {
+ free(buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ntlm->n_type_2 = curlx_uztoul(size);
+ memcpy(ntlm->type_2, buffer, size);
+#else
+ ntlm->flags = 0;
+
+ if((size < 32) ||
+ (memcmp(buffer, NTLMSSP_SIGNATURE, 8) != 0) ||
+ (memcmp(buffer + 8, type2_marker, sizeof(type2_marker)) != 0)) {
+ /* This was not a good enough type-2 message */
+ free(buffer);
+ infof(data, "NTLM handshake failure (bad type-2 message)\n");
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ ntlm->flags = readint_le(&buffer[20]);
+ memcpy(ntlm->nonce, &buffer[24], 8);
+
+ DEBUG_OUT({
+ fprintf(stderr, "**** TYPE2 header flags=0x%08.8lx ", ntlm->flags);
+ ntlm_print_flags(stderr, ntlm->flags);
+ fprintf(stderr, "\n nonce=");
+ ntlm_print_hex(stderr, (char *)ntlm->nonce, 8);
+ fprintf(stderr, "\n****\n");
+ fprintf(stderr, "**** Header %s\n ", header);
+ });
+#endif
+ free(buffer);
+
+ return CURLE_OK;
+}
+
+#ifdef USE_WINDOWS_SSPI
+void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm)
+{
+ Curl_safefree(ntlm->type_2);
+ if(ntlm->has_handles) {
+ s_pSecFn->DeleteSecurityContext(&ntlm->c_handle);
+ s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+ ntlm->has_handles = 0;
+ }
+ if(ntlm->p_identity) {
+ Curl_safefree(ntlm->identity.User);
+ Curl_safefree(ntlm->identity.Password);
+ Curl_safefree(ntlm->identity.Domain);
+ ntlm->p_identity = NULL;
+ }
+}
+#endif
+
+#ifndef USE_WINDOWS_SSPI
+/* copy the source to the destination and fill in zeroes in every
+ other destination byte! */
+static void unicodecpy(unsigned char *dest,
+ const char *src, size_t length)
+{
+ size_t i;
+ for(i = 0; i < length; i++) {
+ dest[2 * i] = (unsigned char)src[i];
+ dest[2 * i + 1] = '\0';
+ }
+}
+#endif
+
+/*
+ * Curl_ntlm_create_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
+ * or IMAP) server, using the appropriate compile time crypo API.
+ *
+ * Parameters:
+ *
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The ntlm data struct being used and modified.
+ * 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_ntlm_create_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen)
+{
+ /* NTLM type-1 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x01000000)
+ 12 Flags long
+ (16) Supplied Domain security buffer (*)
+ (24) Supplied Workstation security buffer (*)
+ (32) OS Version Structure 8 bytes (*)
+ (32) (40) Start of data block (*)
+ (*) -> Optional
+ */
+
+ unsigned char ntlmbuf[NTLM_BUFSIZE];
+ size_t size;
+
+#ifdef USE_WINDOWS_SSPI
+
+ SecBuffer buf;
+ SecBufferDesc desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ xcharp_u useranddomain;
+ xcharp_u user, dup_user;
+ xcharp_u domain, dup_domain;
+ xcharp_u passwd, dup_passwd;
+ size_t domlen = 0;
+ TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
+
+ domain.const_tchar_ptr = TEXT("");
+
+ Curl_ntlm_sspi_cleanup(ntlm);
+
+ if(userp && *userp) {
+
+ /* null initialize ntlm identity's data to allow proper cleanup */
+ ntlm->p_identity = &ntlm->identity;
+ memset(ntlm->p_identity, 0, sizeof(*ntlm->p_identity));
+
+ useranddomain.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)userp);
+ if(!useranddomain.tchar_ptr)
+ return CURLE_OUT_OF_MEMORY;
+
+ user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('\\'));
+ if(!user.const_tchar_ptr)
+ user.const_tchar_ptr = _tcschr(useranddomain.const_tchar_ptr, TEXT('/'));
+
+ if(user.tchar_ptr) {
+ domain.tchar_ptr = useranddomain.tchar_ptr;
+ domlen = user.tchar_ptr - useranddomain.tchar_ptr;
+ user.tchar_ptr++;
+ }
+ else {
+ user.tchar_ptr = useranddomain.tchar_ptr;
+ domain.const_tchar_ptr = TEXT("");
+ domlen = 0;
+ }
+
+ /* setup ntlm identity's user and length */
+ dup_user.tchar_ptr = _tcsdup(user.tchar_ptr);
+ if(!dup_user.tchar_ptr) {
+ Curl_unicodefree(useranddomain.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ntlm->identity.User = dup_user.tbyte_ptr;
+ ntlm->identity.UserLength = curlx_uztoul(_tcslen(dup_user.tchar_ptr));
+ dup_user.tchar_ptr = NULL;
+
+ /* setup ntlm identity's domain and length */
+ dup_domain.tchar_ptr = malloc(sizeof(TCHAR) * (domlen + 1));
+ if(!dup_domain.tchar_ptr) {
+ Curl_unicodefree(useranddomain.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ _tcsncpy(dup_domain.tchar_ptr, domain.tchar_ptr, domlen);
+ *(dup_domain.tchar_ptr + domlen) = TEXT('\0');
+ ntlm->identity.Domain = dup_domain.tbyte_ptr;
+ ntlm->identity.DomainLength = curlx_uztoul(domlen);
+ dup_domain.tchar_ptr = NULL;
+
+ Curl_unicodefree(useranddomain.tchar_ptr);
+
+ /* setup ntlm identity's password and length */
+ passwd.tchar_ptr = Curl_convert_UTF8_to_tchar((char *)passwdp);
+ if(!passwd.tchar_ptr)
+ return CURLE_OUT_OF_MEMORY;
+ dup_passwd.tchar_ptr = _tcsdup(passwd.tchar_ptr);
+ if(!dup_passwd.tchar_ptr) {
+ Curl_unicodefree(passwd.tchar_ptr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ntlm->identity.Password = dup_passwd.tbyte_ptr;
+ ntlm->identity.PasswordLength =
+ curlx_uztoul(_tcslen(dup_passwd.tchar_ptr));
+ dup_passwd.tchar_ptr = NULL;
+
+ Curl_unicodefree(passwd.tchar_ptr);
+
+ /* setup ntlm identity's flags */
+ ntlm->identity.Flags = SECFLAG_WINNT_AUTH_IDENTITY;
+ }
+ else
+ ntlm->p_identity = NULL;
+
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT("NTLM"),
+ SECPKG_CRED_OUTBOUND, NULL,
+ ntlm->p_identity, NULL, NULL,
+ &ntlm->handle, &tsDummy);
+ if(status != SEC_E_OK)
+ return CURLE_OUT_OF_MEMORY;
+
+ desc.ulVersion = SECBUFFER_VERSION;
+ desc.cBuffers = 1;
+ desc.pBuffers = &buf;
+ buf.cbBuffer = NTLM_BUFSIZE;
+ buf.BufferType = SECBUFFER_TOKEN;
+ buf.pvBuffer = ntlmbuf;
+
+ status = s_pSecFn->InitializeSecurityContext(&ntlm->handle, NULL,
+ (TCHAR *) TEXT(""),
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONNECTION,
+ 0, SECURITY_NETWORK_DREP,
+ NULL, 0,
+ &ntlm->c_handle, &desc,
+ &attrs, &tsDummy);
+
+ if(status == SEC_I_COMPLETE_AND_CONTINUE ||
+ status == SEC_I_CONTINUE_NEEDED)
+ s_pSecFn->CompleteAuthToken(&ntlm->c_handle, &desc);
+ else if(status != SEC_E_OK) {
+ s_pSecFn->FreeCredentialsHandle(&ntlm->handle);
+ return CURLE_RECV_ERROR;
+ }
+
+ ntlm->has_handles = 1;
+ size = buf.cbBuffer;
+
+#else
+
+ const char *host = ""; /* empty */
+ const char *domain = ""; /* empty */
+ size_t hostlen = 0;
+ size_t domlen = 0;
+ size_t hostoff = 0;
+ size_t domoff = hostoff + hostlen; /* This is 0: remember that host and
+ domain are empty */
+ (void)userp;
+ (void)passwdp;
+ (void)ntlm;
+
+#if USE_NTLM2SESSION
+#define NTLM2FLAG NTLMFLAG_NEGOTIATE_NTLM2_KEY
+#else
+#define NTLM2FLAG 0
+#endif
+ snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x01%c%c%c" /* 32-bit type = 1 */
+ "%c%c%c%c" /* 32-bit NTLM flag field */
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host name offset */
+ "%c%c" /* 2 zeroes */
+ "%s" /* host name */
+ "%s", /* domain string */
+ 0, /* trailing zero */
+ 0, 0, 0, /* part of type-1 long */
+
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0, 0,
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0, 0,
+ host, /* this is empty */
+ domain /* this is empty */);
+
+ /* Initial packet length */
+ size = 32 + hostlen + domlen;
+
+#endif
+
+ DEBUG_OUT({
+ fprintf(stderr, "* TYPE1 header flags=0x%02.2x%02.2x%02.2x%02.2x "
+ "0x%08.8x ",
+ LONGQUARTET(NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN),
+ NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+ ntlm_print_flags(stderr,
+ NTLMFLAG_NEGOTIATE_OEM |
+ NTLMFLAG_REQUEST_TARGET |
+ NTLMFLAG_NEGOTIATE_NTLM_KEY |
+ NTLM2FLAG |
+ NTLMFLAG_NEGOTIATE_ALWAYS_SIGN);
+ fprintf(stderr, "\n****\n");
+ });
+
+ /* Return with binary blob encoded into base64 */
+ return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+}
+
+/*
+ * Curl_ntlm_create_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient, be it a HTTP or SASL based (such as SMTP, POP3
+ * or IMAP) server, using the appropriate compile time crypo API.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The ntlm data struct being used and modified.
+ * 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_ntlm_create_type3_message(struct SessionHandle *data,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen)
+{
+ /* NTLM type-3 message structure:
+
+ Index Description Content
+ 0 NTLMSSP Signature Null-terminated ASCII "NTLMSSP"
+ (0x4e544c4d53535000)
+ 8 NTLM Message Type long (0x03000000)
+ 12 LM/LMv2 Response security buffer
+ 20 NTLM/NTLMv2 Response security buffer
+ 28 Target Name security buffer
+ 36 User Name security buffer
+ 44 Workstation Name security buffer
+ (52) Session Key security buffer (*)
+ (60) Flags long (*)
+ (64) OS Version Structure 8 bytes (*)
+ 52 (64) (72) Start of data block
+ (*) -> Optional
+ */
+
+ unsigned char ntlmbuf[NTLM_BUFSIZE];
+ size_t size;
+
+#ifdef USE_WINDOWS_SSPI
+ SecBuffer type_2;
+ SecBuffer type_3;
+ SecBufferDesc type_2_desc;
+ SecBufferDesc type_3_desc;
+ SECURITY_STATUS status;
+ unsigned long attrs;
+ TimeStamp tsDummy; /* For Windows 9x compatibility of SSPI calls */
+
+ (void)passwdp;
+ (void)userp;
+ (void)data;
+
+ type_2_desc.ulVersion = type_3_desc.ulVersion = SECBUFFER_VERSION;
+ type_2_desc.cBuffers = type_3_desc.cBuffers = 1;
+ type_2_desc.pBuffers = &type_2;
+ type_3_desc.pBuffers = &type_3;
+
+ type_2.BufferType = SECBUFFER_TOKEN;
+ type_2.pvBuffer = ntlm->type_2;
+ type_2.cbBuffer = ntlm->n_type_2;
+ type_3.BufferType = SECBUFFER_TOKEN;
+ type_3.pvBuffer = ntlmbuf;
+ type_3.cbBuffer = NTLM_BUFSIZE;
+
+ status = s_pSecFn->InitializeSecurityContext(&ntlm->handle,
+ &ntlm->c_handle,
+ (TCHAR *) TEXT(""),
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONNECTION,
+ 0, SECURITY_NETWORK_DREP,
+ &type_2_desc,
+ 0, &ntlm->c_handle,
+ &type_3_desc,
+ &attrs, &tsDummy);
+ if(status != SEC_E_OK)
+ return CURLE_RECV_ERROR;
+
+ size = type_3.cbBuffer;
+
+ Curl_ntlm_sspi_cleanup(ntlm);
+
+#else
+ int lmrespoff;
+ unsigned char lmresp[24]; /* fixed-size */
+#if USE_NTRESPONSES
+ int ntrespoff;
+ unsigned char ntresp[24]; /* fixed-size */
+#endif
+ bool unicode = (ntlm->flags & NTLMFLAG_NEGOTIATE_UNICODE) ? TRUE : FALSE;
+ char host[HOSTNAME_MAX + 1] = "";
+ const char *user;
+ const char *domain = "";
+ size_t hostoff = 0;
+ size_t useroff = 0;
+ size_t domoff = 0;
+ size_t hostlen = 0;
+ size_t userlen = 0;
+ size_t domlen = 0;
+ CURLcode res;
+
+ user = strchr(userp, '\\');
+ if(!user)
+ user = strchr(userp, '/');
+
+ if(user) {
+ domain = userp;
+ domlen = (user - domain);
+ user++;
+ }
+ else
+ user = userp;
+
+ if(user)
+ userlen = strlen(user);
+
+ /* Get the machine's un-qualified host name as NTLM doesn't like the fully
+ qualified domain name */
+ if(Curl_gethostname(host, sizeof(host))) {
+ infof(data, "gethostname() failed, continuing without!\n");
+ hostlen = 0;
+ }
+ else {
+ hostlen = strlen(host);
+ }
+
+ if(unicode) {
+ domlen = domlen * 2;
+ userlen = userlen * 2;
+ hostlen = hostlen * 2;
+ }
+
+#if USE_NTLM2SESSION
+ /* We don't support NTLM2 if we don't have USE_NTRESPONSES */
+ if(ntlm->flags & NTLMFLAG_NEGOTIATE_NTLM2_KEY) {
+ unsigned char ntbuffer[0x18];
+ unsigned char tmp[0x18];
+ unsigned char md5sum[MD5_DIGEST_LENGTH];
+ unsigned char entropy[8];
+
+ /* Need to create 8 bytes random data */
+ Curl_ssl_random(data, entropy, sizeof(entropy));
+
+ /* 8 bytes random data as challenge in lmresp */
+ memcpy(lmresp, entropy, 8);
+
+ /* Pad with zeros */
+ memset(lmresp + 8, 0, 0x10);
+
+ /* Fill tmp with challenge(nonce?) + entropy */
+ memcpy(tmp, &ntlm->nonce[0], 8);
+ memcpy(tmp + 8, entropy, 8);
+
+ Curl_ssl_md5sum(tmp, 16, md5sum, MD5_DIGEST_LENGTH);
+
+ /* We shall only use the first 8 bytes of md5sum, but the des
+ code in Curl_ntlm_core_lm_resp only encrypt the first 8 bytes */
+ if(CURLE_OUT_OF_MEMORY ==
+ Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ntlm_core_lm_resp(ntbuffer, md5sum, ntresp);
+
+ /* End of NTLM2 Session code */
+ }
+ else
+#endif
+ {
+
+#if USE_NTRESPONSES
+ unsigned char ntbuffer[0x18];
+#endif
+ unsigned char lmbuffer[0x18];
+
+#if USE_NTRESPONSES
+ if(CURLE_OUT_OF_MEMORY ==
+ Curl_ntlm_core_mk_nt_hash(data, passwdp, ntbuffer))
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], ntresp);
+#endif
+
+ Curl_ntlm_core_mk_lm_hash(data, passwdp, lmbuffer);
+ Curl_ntlm_core_lm_resp(lmbuffer, &ntlm->nonce[0], lmresp);
+ /* A safer but less compatible alternative is:
+ * Curl_ntlm_core_lm_resp(ntbuffer, &ntlm->nonce[0], lmresp);
+ * See http://davenport.sourceforge.net/ntlm.html#ntlmVersion2 */
+ }
+
+ lmrespoff = 64; /* size of the message header */
+#if USE_NTRESPONSES
+ ntrespoff = lmrespoff + 0x18;
+ domoff = ntrespoff + 0x18;
+#else
+ domoff = lmrespoff + 0x18;
+#endif
+ useroff = domoff + domlen;
+ hostoff = useroff + userlen;
+
+ /* Create the big type-3 message binary blob */
+ size = snprintf((char *)ntlmbuf, NTLM_BUFSIZE,
+ NTLMSSP_SIGNATURE "%c"
+ "\x03%c%c%c" /* 32-bit type = 3 */
+
+ "%c%c" /* LanManager length */
+ "%c%c" /* LanManager allocated space */
+ "%c%c" /* LanManager offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* NT-response length */
+ "%c%c" /* NT-response allocated space */
+ "%c%c" /* NT-response offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* domain length */
+ "%c%c" /* domain allocated space */
+ "%c%c" /* domain name offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* user length */
+ "%c%c" /* user allocated space */
+ "%c%c" /* user offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* host length */
+ "%c%c" /* host allocated space */
+ "%c%c" /* host offset */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c" /* session key length (unknown purpose) */
+ "%c%c" /* session key allocated space (unknown purpose) */
+ "%c%c" /* session key offset (unknown purpose) */
+ "%c%c" /* 2 zeroes */
+
+ "%c%c%c%c", /* flags */
+
+ /* domain string */
+ /* user string */
+ /* host string */
+ /* LanManager response */
+ /* NT response */
+
+ 0, /* zero termination */
+ 0, 0, 0, /* type-3 long, the 24 upper bits */
+
+ SHORTPAIR(0x18), /* LanManager response length, twice */
+ SHORTPAIR(0x18),
+ SHORTPAIR(lmrespoff),
+ 0x0, 0x0,
+
+#if USE_NTRESPONSES
+ SHORTPAIR(0x18), /* NT-response length, twice */
+ SHORTPAIR(0x18),
+ SHORTPAIR(ntrespoff),
+ 0x0, 0x0,
+#else
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+#endif
+ SHORTPAIR(domlen),
+ SHORTPAIR(domlen),
+ SHORTPAIR(domoff),
+ 0x0, 0x0,
+
+ SHORTPAIR(userlen),
+ SHORTPAIR(userlen),
+ SHORTPAIR(useroff),
+ 0x0, 0x0,
+
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostlen),
+ SHORTPAIR(hostoff),
+ 0x0, 0x0,
+
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+ 0x0, 0x0,
+
+ LONGQUARTET(ntlm->flags));
+
+ DEBUGASSERT(size == 64);
+ DEBUGASSERT(size == (size_t)lmrespoff);
+
+ /* We append the binary hashes */
+ if(size < (NTLM_BUFSIZE - 0x18)) {
+ memcpy(&ntlmbuf[size], lmresp, 0x18);
+ size += 0x18;
+ }
+
+ DEBUG_OUT({
+ fprintf(stderr, "**** TYPE3 header lmresp=");
+ ntlm_print_hex(stderr, (char *)&ntlmbuf[lmrespoff], 0x18);
+ });
+
+#if USE_NTRESPONSES
+ if(size < (NTLM_BUFSIZE - 0x18)) {
+ DEBUGASSERT(size == (size_t)ntrespoff);
+ memcpy(&ntlmbuf[size], ntresp, 0x18);
+ size += 0x18;
+ }
+
+ DEBUG_OUT({
+ fprintf(stderr, "\n ntresp=");
+ ntlm_print_hex(stderr, (char *)&ntlmbuf[ntrespoff], 0x18);
+ });
+
+#endif
+
+ DEBUG_OUT({
+ fprintf(stderr, "\n flags=0x%02.2x%02.2x%02.2x%02.2x 0x%08.8x ",
+ LONGQUARTET(ntlm->flags), ntlm->flags);
+ ntlm_print_flags(stderr, ntlm->flags);
+ fprintf(stderr, "\n****\n");
+ });
+
+ /* Make sure that the domain, user and host strings fit in the
+ buffer before we copy them there. */
+ if(size + userlen + domlen + hostlen >= NTLM_BUFSIZE) {
+ failf(data, "user + domain + host name too big");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ DEBUGASSERT(size == domoff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], domain, domlen / 2);
+ else
+ memcpy(&ntlmbuf[size], domain, domlen);
+
+ size += domlen;
+
+ DEBUGASSERT(size == useroff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], user, userlen / 2);
+ else
+ memcpy(&ntlmbuf[size], user, userlen);
+
+ size += userlen;
+
+ DEBUGASSERT(size == hostoff);
+ if(unicode)
+ unicodecpy(&ntlmbuf[size], host, hostlen / 2);
+ else
+ memcpy(&ntlmbuf[size], host, hostlen);
+
+ size += hostlen;
+
+ /* Convert domain, user, and host to ASCII but leave the rest as-is */
+ res = Curl_convert_to_network(data, (char *)&ntlmbuf[domoff],
+ size - domoff);
+ if(res)
+ return CURLE_CONV_FAILED;
+
+#endif
+
+ /* Return with binary blob encoded into base64 */
+ return Curl_base64_encode(NULL, (char *)ntlmbuf, size, outptr, outlen);
+}
+
+#endif /* USE_NTLM */
diff --git a/libs/libcurl/src/curl_ntlm_msgs.h b/libs/libcurl/src/curl_ntlm_msgs.h
new file mode 100644
index 0000000000..e7d185dea5
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_msgs.h
@@ -0,0 +1,178 @@
+#ifndef HEADER_CURL_NTLM_MSGS_H
+#define HEADER_CURL_NTLM_MSGS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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_NTLM
+
+/* This is to generate a base64 encoded NTLM type-1 message */
+CURLcode Curl_ntlm_create_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen);
+
+/* This is to generate a base64 encoded NTLM type-3 message */
+CURLcode Curl_ntlm_create_type3_message(struct SessionHandle *data,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen);
+
+/* This is to decode a NTLM type-2 message */
+CURLcode Curl_ntlm_decode_type2_message(struct SessionHandle *data,
+ const char* header,
+ struct ntlmdata* ntlm);
+
+/* This is to clean up the ntlm data structure */
+#ifdef USE_WINDOWS_SSPI
+void Curl_ntlm_sspi_cleanup(struct ntlmdata *ntlm);
+#else
+#define Curl_ntlm_sspi_cleanup(x)
+#endif
+
+/* NTLM buffer fixed size, large enough for long user + host + domain */
+#define NTLM_BUFSIZE 1024
+
+/* Stuff only required for curl_ntlm_msgs.c */
+#ifdef BUILDING_CURL_NTLM_MSGS_C
+
+/* Flag bits definitions based on http://davenport.sourceforge.net/ntlm.html */
+
+#define NTLMFLAG_NEGOTIATE_UNICODE (1<<0)
+/* Indicates that Unicode strings are supported for use in security buffer
+ data. */
+
+#define NTLMFLAG_NEGOTIATE_OEM (1<<1)
+/* Indicates that OEM strings are supported for use in security buffer data. */
+
+#define NTLMFLAG_REQUEST_TARGET (1<<2)
+/* Requests that the server's authentication realm be included in the Type 2
+ message. */
+
+/* unknown (1<<3) */
+#define NTLMFLAG_NEGOTIATE_SIGN (1<<4)
+/* Specifies that authenticated communication between the client and server
+ should carry a digital signature (message integrity). */
+
+#define NTLMFLAG_NEGOTIATE_SEAL (1<<5)
+/* Specifies that authenticated communication between the client and server
+ should be encrypted (message confidentiality). */
+
+#define NTLMFLAG_NEGOTIATE_DATAGRAM_STYLE (1<<6)
+/* Indicates that datagram authentication is being used. */
+
+#define NTLMFLAG_NEGOTIATE_LM_KEY (1<<7)
+/* Indicates that the LAN Manager session key should be used for signing and
+ sealing authenticated communications. */
+
+#define NTLMFLAG_NEGOTIATE_NETWARE (1<<8)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_NTLM_KEY (1<<9)
+/* Indicates that NTLM authentication is being used. */
+
+/* unknown (1<<10) */
+
+#define NTLMFLAG_NEGOTIATE_ANONYMOUS (1<<11)
+/* Sent by the client in the Type 3 message to indicate that an anonymous
+ context has been established. This also affects the response fields. */
+
+#define NTLMFLAG_NEGOTIATE_DOMAIN_SUPPLIED (1<<12)
+/* Sent by the client in the Type 1 message to indicate that a desired
+ authentication realm is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_WORKSTATION_SUPPLIED (1<<13)
+/* Sent by the client in the Type 1 message to indicate that the client
+ workstation's name is included in the message. */
+
+#define NTLMFLAG_NEGOTIATE_LOCAL_CALL (1<<14)
+/* Sent by the server to indicate that the server and client are on the same
+ machine. Implies that the client may use a pre-established local security
+ context rather than responding to the challenge. */
+
+#define NTLMFLAG_NEGOTIATE_ALWAYS_SIGN (1<<15)
+/* Indicates that authenticated communication between the client and server
+ should be signed with a "dummy" signature. */
+
+#define NTLMFLAG_TARGET_TYPE_DOMAIN (1<<16)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a domain. */
+
+#define NTLMFLAG_TARGET_TYPE_SERVER (1<<17)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a server. */
+
+#define NTLMFLAG_TARGET_TYPE_SHARE (1<<18)
+/* Sent by the server in the Type 2 message to indicate that the target
+ authentication realm is a share. Presumably, this is for share-level
+ authentication. Usage is unclear. */
+
+#define NTLMFLAG_NEGOTIATE_NTLM2_KEY (1<<19)
+/* Indicates that the NTLM2 signing and sealing scheme should be used for
+ protecting authenticated communications. */
+
+#define NTLMFLAG_REQUEST_INIT_RESPONSE (1<<20)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_ACCEPT_RESPONSE (1<<21)
+/* unknown purpose */
+
+#define NTLMFLAG_REQUEST_NONNT_SESSION_KEY (1<<22)
+/* unknown purpose */
+
+#define NTLMFLAG_NEGOTIATE_TARGET_INFO (1<<23)
+/* Sent by the server in the Type 2 message to indicate that it is including a
+ Target Information block in the message. */
+
+/* unknown (1<24) */
+/* unknown (1<25) */
+/* unknown (1<26) */
+/* unknown (1<27) */
+/* unknown (1<28) */
+
+#define NTLMFLAG_NEGOTIATE_128 (1<<29)
+/* Indicates that 128-bit encryption is supported. */
+
+#define NTLMFLAG_NEGOTIATE_KEY_EXCHANGE (1<<30)
+/* Indicates that the client will provide an encrypted master key in
+ the "Session Key" field of the Type 3 message. */
+
+#define NTLMFLAG_NEGOTIATE_56 (1<<31)
+/* Indicates that 56-bit encryption is supported. */
+
+#ifdef UNICODE
+# define SECFLAG_WINNT_AUTH_IDENTITY \
+ (unsigned long)SEC_WINNT_AUTH_IDENTITY_UNICODE
+#else
+# define SECFLAG_WINNT_AUTH_IDENTITY \
+ (unsigned long)SEC_WINNT_AUTH_IDENTITY_ANSI
+#endif
+
+#endif /* BUILDING_CURL_NTLM_MSGS_C */
+
+#endif /* USE_NTLM */
+
+#endif /* HEADER_CURL_NTLM_MSGS_H */
diff --git a/libs/libcurl/src/curl_ntlm_wb.c b/libs/libcurl/src/curl_ntlm_wb.c
new file mode 100644
index 0000000000..b1c20e1b3b
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_wb.c
@@ -0,0 +1,391 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+
+/*
+ * NTLM details:
+ *
+ * http://davenport.sourceforge.net/ntlm.html
+ * http://www.innovation.ch/java/ntlm.html
+ */
+
+#define DEBUG_ME 0
+
+#ifdef HAVE_SYS_WAIT_H
+#include <sys/wait.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "curl_ntlm_wb.h"
+#include "url.h"
+#include "strerror.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if DEBUG_ME
+# define DEBUG_OUT(x) x
+#else
+# define DEBUG_OUT(x) Curl_nop_stmt
+#endif
+
+/* Portable 'sclose_nolog' used only in child process instead of 'sclose'
+ to avoid fooling the socket leak detector */
+#if defined(HAVE_CLOSESOCKET)
+# define sclose_nolog(x) closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+# define sclose_nolog(x) CloseSocket((x))
+#else
+# define sclose_nolog(x) close((x))
+#endif
+
+void Curl_ntlm_wb_cleanup(struct connectdata *conn)
+{
+ if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD) {
+ sclose(conn->ntlm_auth_hlpr_socket);
+ conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ }
+
+ if(conn->ntlm_auth_hlpr_pid) {
+ int i;
+ for(i = 0; i < 4; i++) {
+ pid_t ret = waitpid(conn->ntlm_auth_hlpr_pid, NULL, WNOHANG);
+ if(ret == conn->ntlm_auth_hlpr_pid || errno == ECHILD)
+ break;
+ switch(i) {
+ case 0:
+ kill(conn->ntlm_auth_hlpr_pid, SIGTERM);
+ break;
+ case 1:
+ /* Give the process another moment to shut down cleanly before
+ bringing down the axe */
+ Curl_wait_ms(1);
+ break;
+ case 2:
+ kill(conn->ntlm_auth_hlpr_pid, SIGKILL);
+ break;
+ case 3:
+ break;
+ }
+ }
+ conn->ntlm_auth_hlpr_pid = 0;
+ }
+
+ Curl_safefree(conn->challenge_header);
+ conn->challenge_header = NULL;
+ Curl_safefree(conn->response_header);
+ conn->response_header = NULL;
+}
+
+static CURLcode ntlm_wb_init(struct connectdata *conn, const char *userp)
+{
+ curl_socket_t sockfds[2];
+ pid_t child_pid;
+ const char *username;
+ char *slash, *domain = NULL;
+ const char *ntlm_auth = NULL;
+ char *ntlm_auth_alloc = NULL;
+ int error;
+
+ /* Return if communication with ntlm_auth already set up */
+ if(conn->ntlm_auth_hlpr_socket != CURL_SOCKET_BAD ||
+ conn->ntlm_auth_hlpr_pid)
+ return CURLE_OK;
+
+ username = userp;
+ slash = strpbrk(username, "\\/");
+ if(slash) {
+ if((domain = strdup(username)) == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ slash = domain + (slash - username);
+ *slash = '\0';
+ username = username + (slash - domain) + 1;
+ }
+
+ /* For testing purposes, when DEBUGBUILD is defined and environment
+ variable CURL_NTLM_WB_FILE is set a fake_ntlm is used to perform
+ NTLM challenge/response which only accepts commands and output
+ strings pre-written in test case definitions */
+#ifdef DEBUGBUILD
+ ntlm_auth_alloc = curl_getenv("CURL_NTLM_WB_FILE");
+ if(ntlm_auth_alloc)
+ ntlm_auth = ntlm_auth_alloc;
+ else
+#endif
+ ntlm_auth = NTLM_WB_FILE;
+
+ if(access(ntlm_auth, X_OK) != 0) {
+ error = ERRNO;
+ failf(conn->data, "Could not access ntlm_auth: %s errno %d: %s",
+ ntlm_auth, error, Curl_strerror(conn, error));
+ goto done;
+ }
+
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, sockfds)) {
+ error = ERRNO;
+ failf(conn->data, "Could not open socket pair. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ goto done;
+ }
+
+ child_pid = fork();
+ if(child_pid == -1) {
+ error = ERRNO;
+ sclose(sockfds[0]);
+ sclose(sockfds[1]);
+ failf(conn->data, "Could not fork. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ goto done;
+ }
+ else if(!child_pid) {
+ /*
+ * child process
+ */
+
+ /* Don't use sclose in the child since it fools the socket leak detector */
+ sclose_nolog(sockfds[0]);
+ if(dup2(sockfds[1], STDIN_FILENO) == -1) {
+ error = ERRNO;
+ failf(conn->data, "Could not redirect child stdin. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ if(dup2(sockfds[1], STDOUT_FILENO) == -1) {
+ error = ERRNO;
+ failf(conn->data, "Could not redirect child stdout. errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ if(domain)
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ "--domain", domain,
+ NULL);
+ else
+ execl(ntlm_auth, ntlm_auth,
+ "--helper-protocol", "ntlmssp-client-1",
+ "--use-cached-creds",
+ "--username", username,
+ NULL);
+
+ error = ERRNO;
+ sclose_nolog(sockfds[1]);
+ failf(conn->data, "Could not execl(). errno %d: %s",
+ error, Curl_strerror(conn, error));
+ exit(1);
+ }
+
+ sclose(sockfds[1]);
+ conn->ntlm_auth_hlpr_socket = sockfds[0];
+ conn->ntlm_auth_hlpr_pid = child_pid;
+ Curl_safefree(domain);
+ Curl_safefree(ntlm_auth_alloc);
+ return CURLE_OK;
+
+done:
+ Curl_safefree(domain);
+ Curl_safefree(ntlm_auth_alloc);
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+static CURLcode ntlm_wb_response(struct connectdata *conn,
+ const char *input, curlntlm state)
+{
+ ssize_t size;
+ char buf[200]; /* enough, type 1, 3 message length is less then 200 */
+ char *tmpbuf = buf;
+ size_t len_in = strlen(input), len_out = sizeof(buf);
+
+ while(len_in > 0) {
+ ssize_t written = swrite(conn->ntlm_auth_hlpr_socket, input, len_in);
+ if(written == -1) {
+ /* Interrupted by a signal, retry it */
+ if(errno == EINTR)
+ continue;
+ /* write failed if other errors happen */
+ goto done;
+ }
+ input += written;
+ len_in -= written;
+ }
+ /* Read one line */
+ while(len_out > 0) {
+ size = sread(conn->ntlm_auth_hlpr_socket, tmpbuf, len_out);
+ if(size == -1) {
+ if(errno == EINTR)
+ continue;
+ goto done;
+ }
+ else if(size == 0)
+ goto done;
+ else if(tmpbuf[size - 1] == '\n') {
+ tmpbuf[size - 1] = '\0';
+ goto wrfinish;
+ }
+ tmpbuf += size;
+ len_out -= size;
+ }
+ goto done;
+wrfinish:
+ /* Samba/winbind installed but not configured */
+ if(state == NTLMSTATE_TYPE1 &&
+ size == 3 &&
+ buf[0] == 'P' && buf[1] == 'W')
+ return CURLE_REMOTE_ACCESS_DENIED;
+ /* invalid response */
+ if(size < 4)
+ goto done;
+ if(state == NTLMSTATE_TYPE1 &&
+ (buf[0]!='Y' || buf[1]!='R' || buf[2]!=' '))
+ goto done;
+ if(state == NTLMSTATE_TYPE2 &&
+ (buf[0]!='K' || buf[1]!='K' || buf[2]!=' ') &&
+ (buf[0]!='A' || buf[1]!='F' || buf[2]!=' '))
+ goto done;
+
+ conn->response_header = aprintf("NTLM %.*s", size - 4, buf + 3);
+ return CURLE_OK;
+done:
+ return CURLE_REMOTE_ACCESS_DENIED;
+}
+
+/*
+ * This is for creating ntlm header output by delegating challenge/response
+ * to Samba's winbind daemon helper ntlm_auth.
+ */
+CURLcode Curl_output_ntlm_wb(struct connectdata *conn,
+ bool proxy)
+{
+ /* point to the address of the pointer that holds the string to send to the
+ server, which is for a plain host or for a HTTP proxy */
+ char **allocuserpwd;
+ /* point to the name and password for this */
+ const char *userp;
+ /* point to the correct struct with this */
+ struct ntlmdata *ntlm;
+ struct auth *authp;
+
+ CURLcode res = CURLE_OK;
+ char *input;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(conn->data);
+
+ if(proxy) {
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->proxyuser;
+ ntlm = &conn->proxyntlm;
+ authp = &conn->data->state.authproxy;
+ }
+ else {
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ ntlm = &conn->ntlm;
+ authp = &conn->data->state.authhost;
+ }
+ authp->done = FALSE;
+
+ /* not set means empty */
+ if(!userp)
+ userp="";
+
+ switch(ntlm->state) {
+ case NTLMSTATE_TYPE1:
+ default:
+ /* Use Samba's 'winbind' daemon to support NTLM authentication,
+ * by delegating the NTLM challenge/response protocal to a helper
+ * in ntlm_auth.
+ * http://devel.squid-cache.org/ntlm/squid_helper_protocol.html
+ * http://www.samba.org/samba/docs/man/manpages-3/winbindd.8.html
+ * http://www.samba.org/samba/docs/man/manpages-3/ntlm_auth.1.html
+ * Preprocessor symbol 'NTLM_WB_ENABLED' is defined when this
+ * feature is enabled and 'NTLM_WB_FILE' symbol holds absolute
+ * filename of ntlm_auth helper.
+ * If NTLM authentication using winbind fails, go back to original
+ * request handling process.
+ */
+ /* Create communication with ntlm_auth */
+ res = ntlm_wb_init(conn, userp);
+ if(res)
+ return res;
+ res = ntlm_wb_response(conn, "YR\n", ntlm->state);
+ if(res)
+ return res;
+
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
+ proxy ? "Proxy-" : "",
+ conn->response_header);
+ DEBUG_OUT(fprintf(stderr, "**** Header %s\n ", *allocuserpwd));
+ Curl_safefree(conn->response_header);
+ conn->response_header = NULL;
+ break;
+ case NTLMSTATE_TYPE2:
+ input = aprintf("TT %s", conn->challenge_header);
+ if(!input)
+ return CURLE_OUT_OF_MEMORY;
+ res = ntlm_wb_response(conn, input, ntlm->state);
+ free(input);
+ input = NULL;
+ if(res)
+ return res;
+
+ Curl_safefree(*allocuserpwd);
+ *allocuserpwd = aprintf("%sAuthorization: %s\r\n",
+ proxy ? "Proxy-" : "",
+ conn->response_header);
+ DEBUG_OUT(fprintf(stderr, "**** %s\n ", *allocuserpwd));
+ ntlm->state = NTLMSTATE_TYPE3; /* we sent a type-3 */
+ authp->done = TRUE;
+ Curl_ntlm_wb_cleanup(conn);
+ break;
+ case NTLMSTATE_TYPE3:
+ /* connection is already authenticated,
+ * don't send a header in future requests */
+ if(*allocuserpwd) {
+ free(*allocuserpwd);
+ *allocuserpwd=NULL;
+ }
+ authp->done = TRUE;
+ break;
+ }
+
+ return CURLE_OK;
+}
+
+#endif /* USE_NTLM && NTLM_WB_ENABLED */
diff --git a/libs/libcurl/src/curl_ntlm_wb.h b/libs/libcurl/src/curl_ntlm_wb.h
new file mode 100644
index 0000000000..db6bc16b73
--- /dev/null
+++ b/libs/libcurl/src/curl_ntlm_wb.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_NTLM_WB_H
+#define HEADER_CURL_NTLM_WB_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+
+/* this is for creating ntlm header output by delegating challenge/response
+ to Samba's winbind daemon helper ntlm_auth */
+CURLcode Curl_output_ntlm_wb(struct connectdata *conn, bool proxy);
+
+void Curl_ntlm_wb_cleanup(struct connectdata *conn);
+
+#endif /* USE_NTLM && NTLM_WB_ENABLED */
+
+#endif /* HEADER_CURL_NTLM_WB_H */
diff --git a/libs/libcurl/src/curl_rtmp.c b/libs/libcurl/src/curl_rtmp.c
new file mode 100644
index 0000000000..45da35ca01
--- /dev/null
+++ b/libs/libcurl/src/curl_rtmp.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
+ *
+ * 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_LIBRTMP
+
+#include "urldata.h"
+#include "nonblock.h" /* for curlx_nonblock */
+#include "progress.h" /* for Curl_pgrsSetUploadSize */
+#include "transfer.h"
+#include "warnless.h"
+#include <curl/curl.h>
+#include <librtmp/rtmp.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"
+
+#ifdef _WIN32
+#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
+#define SET_RCVTIMEO(tv,s) int tv = s*1000
+#else
+#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
+#endif
+
+#define DEF_BUFTIME (2*60*60*1000) /* 2 hours */
+
+static CURLcode rtmp_setup(struct connectdata *conn);
+static CURLcode rtmp_do(struct connectdata *conn, bool *done);
+static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
+static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
+static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
+
+static Curl_recv rtmp_recv;
+static Curl_send rtmp_send;
+
+/*
+ * RTMP protocol handler.h, based on http://rtmpdump.mplayerhq.hu
+ */
+
+const struct Curl_handler Curl_handler_rtmp = {
+ "RTMP", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMP, /* defport */
+ CURLPROTO_RTMP, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpt = {
+ "RTMPT", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPT, /* defport */
+ CURLPROTO_RTMPT, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpe = {
+ "RTMPE", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMP, /* defport */
+ CURLPROTO_RTMPE, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpte = {
+ "RTMPTE", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPT, /* defport */
+ CURLPROTO_RTMPTE, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmps = {
+ "RTMPS", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPS, /* defport */
+ CURLPROTO_RTMPS, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+const struct Curl_handler Curl_handler_rtmpts = {
+ "RTMPTS", /* scheme */
+ rtmp_setup, /* setup_connection */
+ rtmp_do, /* do_it */
+ rtmp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtmp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtmp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_RTMPS, /* defport */
+ CURLPROTO_RTMPTS, /* protocol */
+ PROTOPT_NONE /* flags*/
+};
+
+static CURLcode rtmp_setup(struct connectdata *conn)
+{
+ RTMP *r = RTMP_Alloc();
+
+ if(!r)
+ return CURLE_OUT_OF_MEMORY;
+
+ RTMP_Init(r);
+ RTMP_SetBufferMS(r, DEF_BUFTIME);
+ if(!RTMP_SetupURL(r, conn->data->change.url)) {
+ RTMP_Free(r);
+ return CURLE_URL_MALFORMAT;
+ }
+ conn->proto.generic = r;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
+{
+ RTMP *r = conn->proto.generic;
+ SET_RCVTIMEO(tv,10);
+
+ r->m_sb.sb_socket = conn->sock[FIRSTSOCKET];
+
+ /* We have to know if it's a write before we send the
+ * connect request packet
+ */
+ if(conn->data->set.upload)
+ r->Link.protocol |= RTMP_FEATURE_WRITE;
+
+ /* For plain streams, use the buffer toggle trick to keep data flowing */
+ if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
+ !(r->Link.protocol & RTMP_FEATURE_HTTP))
+ r->Link.lFlags |= RTMP_LF_BUFX;
+
+ curlx_nonblock(r->m_sb.sb_socket, FALSE);
+ setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
+ (char *)&tv, sizeof(tv));
+
+ if(!RTMP_Connect1(r, NULL))
+ return CURLE_FAILED_INIT;
+
+ /* Clients must send a periodic BytesReceived report to the server */
+ r->m_bSendCounter = true;
+
+ *done = TRUE;
+ conn->recv[FIRSTSOCKET] = rtmp_recv;
+ conn->send[FIRSTSOCKET] = rtmp_send;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_do(struct connectdata *conn, bool *done)
+{
+ RTMP *r = conn->proto.generic;
+
+ if(!RTMP_ConnectStream(r, 0))
+ return CURLE_FAILED_INIT;
+
+ if(conn->data->set.upload) {
+ Curl_pgrsSetUploadSize(conn->data, conn->data->set.infilesize);
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+ }
+ else
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ *done = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ (void)conn; /* unused */
+ (void)status; /* unused */
+ (void)premature; /* unused */
+
+ return CURLE_OK;
+}
+
+static CURLcode rtmp_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ RTMP *r = conn->proto.generic;
+ (void)dead_connection;
+ if(r) {
+ conn->proto.generic = NULL;
+ RTMP_Close(r);
+ RTMP_Free(r);
+ }
+ return CURLE_OK;
+}
+
+static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
+ size_t len, CURLcode *err)
+{
+ RTMP *r = conn->proto.generic;
+ ssize_t nread;
+
+ (void)sockindex; /* unused */
+
+ nread = RTMP_Read(r, buf, curlx_uztosi(len));
+ if(nread < 0) {
+ if(r->m_read.status == RTMP_READ_COMPLETE ||
+ r->m_read.status == RTMP_READ_EOF) {
+ conn->data->req.size = conn->data->req.bytecount;
+ nread = 0;
+ }
+ else
+ *err = CURLE_RECV_ERROR;
+ }
+ return nread;
+}
+
+static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
+ const void *buf, size_t len, CURLcode *err)
+{
+ RTMP *r = conn->proto.generic;
+ ssize_t num;
+
+ (void)sockindex; /* unused */
+
+ num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
+ if(num < 0)
+ *err = CURLE_SEND_ERROR;
+
+ return num;
+}
+#endif /* USE_LIBRTMP */
diff --git a/libs/libcurl/src/curl_rtmp.h b/libs/libcurl/src/curl_rtmp.h
new file mode 100644
index 0000000000..4a9e9e60c2
--- /dev/null
+++ b/libs/libcurl/src/curl_rtmp.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_RTMP_H
+#define HEADER_CURL_RTMP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+#ifdef USE_LIBRTMP
+extern const struct Curl_handler Curl_handler_rtmp;
+extern const struct Curl_handler Curl_handler_rtmpt;
+extern const struct Curl_handler Curl_handler_rtmpe;
+extern const struct Curl_handler Curl_handler_rtmpte;
+extern const struct Curl_handler Curl_handler_rtmps;
+extern const struct Curl_handler Curl_handler_rtmpts;
+#endif
+
+#endif /* HEADER_CURL_RTMP_H */
diff --git a/libs/libcurl/src/curl_sasl.c b/libs/libcurl/src/curl_sasl.c
new file mode 100644
index 0000000000..b3ffc66156
--- /dev/null
+++ b/libs/libcurl/src/curl_sasl.c
@@ -0,0 +1,539 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 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.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+#include "urldata.h"
+
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "sslgen.h"
+#include "curl_hmac.h"
+#include "curl_ntlm_msgs.h"
+#include "curl_sasl.h"
+#include "warnless.h"
+#include "curl_memory.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* Retrieves the value for a corresponding key from the challenge string
+ * returns TRUE if the key could be found, FALSE if it does not exists
+ */
+static bool sasl_digest_get_key_value(const unsigned char *chlg,
+ const char *key,
+ char *value,
+ size_t max_val_len,
+ char end_char)
+{
+ char *find_pos;
+ size_t i;
+
+ find_pos = strstr((const char *) chlg, key);
+ if(!find_pos)
+ return FALSE;
+
+ find_pos += strlen(key);
+
+ for(i = 0; *find_pos && *find_pos != end_char && i < max_val_len - 1; ++i)
+ value[i] = *find_pos++;
+ value[i] = '\0';
+
+ return TRUE;
+}
+#endif
+
+/*
+ * Curl_sasl_create_plain_message()
+ *
+ * This is used to generate an already encoded PLAIN message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * 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_plain_message(struct SessionHandle *data,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result;
+ char *plainauth;
+ size_t ulen;
+ size_t plen;
+
+ ulen = strlen(userp);
+ plen = strlen(passwdp);
+
+ plainauth = malloc(2 * ulen + plen + 2);
+ if(!plainauth) {
+ *outlen = 0;
+ *outptr = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Calculate the reply */
+ memcpy(plainauth, userp, ulen);
+ plainauth[ulen] = '\0';
+ memcpy(plainauth + ulen + 1, userp, ulen);
+ plainauth[2 * ulen + 1] = '\0';
+ memcpy(plainauth + 2 * ulen + 2, passwdp, plen);
+
+ /* Base64 encode the reply */
+ result = Curl_base64_encode(data, plainauth, 2 * ulen + plen + 2, outptr,
+ outlen);
+ Curl_safefree(plainauth);
+ return result;
+}
+
+/*
+ * Curl_sasl_create_login_message()
+ *
+ * This is used to generate an already encoded LOGIN message containing the
+ * user name or password ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * valuep [in] - The user name or user's password.
+ * 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_login_message(struct SessionHandle *data,
+ const char *valuep, char **outptr,
+ size_t *outlen)
+{
+ size_t vlen = strlen(valuep);
+
+ if(!vlen) {
+ /* Calculate an empty reply */
+ *outptr = strdup("=");
+ if(*outptr) {
+ *outlen = (size_t) 1;
+ return CURLE_OK;
+ }
+
+ *outlen = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Base64 encode the value */
+ return Curl_base64_encode(data, valuep, vlen, outptr, outlen);
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/*
+ * Curl_sasl_create_cram_md5_message()
+ *
+ * This is used to generate an already encoded CRAM-MD5 response message ready
+ * for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - Pointer to the base64 encoded challenge buffer.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * 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_cram_md5_message(struct SessionHandle *data,
+ const char *chlg64,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = CURLE_OK;
+ size_t chlg64len = strlen(chlg64);
+ unsigned char *chlg = (unsigned char *) NULL;
+ size_t chlglen = 0;
+ HMAC_context *ctxt;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char *response;
+
+ /* Decode the challenge if necessary */
+ if(chlg64len && *chlg64 != '=') {
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+
+ if(result)
+ return result;
+ }
+
+ /* Compute the digest using the password as the key */
+ ctxt = Curl_HMAC_init(Curl_HMAC_MD5,
+ (const unsigned char *) passwdp,
+ curlx_uztoui(strlen(passwdp)));
+
+ if(!ctxt) {
+ Curl_safefree(chlg);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Update the digest with the given challenge */
+ if(chlglen > 0)
+ Curl_HMAC_update(ctxt, chlg, curlx_uztoui(chlglen));
+
+ Curl_safefree(chlg);
+
+ /* Finalise the digest */
+ Curl_HMAC_final(ctxt, digest);
+
+ /* Prepare the 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 */
+ result = Curl_base64_encode(data, response, 0, outptr, outlen);
+
+ Curl_safefree(response);
+ return result;
+}
+
+/*
+ * Curl_sasl_create_digest_md5_message()
+ *
+ * This is used to generate an already encoded DIGEST-MD5 response message
+ * ready for sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - The session handle.
+ * chlg64 [in] - Pointer to the base64 encoded challenge buffer.
+ * userp [in] - The user name.
+ * passdwp [in] - The user's password.
+ * service [in] - The service type such as www, smtp or pop
+ * 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_digest_md5_message(struct SessionHandle *data,
+ const char *chlg64,
+ const char *userp,
+ const char *passwdp,
+ const char *service,
+ char **outptr, size_t *outlen)
+{
+ static const char table16[] = "0123456789abcdef";
+
+ CURLcode result = CURLE_OK;
+ unsigned char *chlg = (unsigned char *) NULL;
+ size_t chlglen = 0;
+ size_t i;
+ MD5_context *ctxt;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char HA1_hex[2 * MD5_DIGEST_LEN + 1];
+ char HA2_hex[2 * MD5_DIGEST_LEN + 1];
+ char resp_hash_hex[2 * MD5_DIGEST_LEN + 1];
+
+ char nonce[64];
+ char realm[128];
+ char alg[64];
+ char nonceCount[] = "00000001";
+ char cnonce[] = "12345678"; /* will be changed */
+ char method[] = "AUTHENTICATE";
+ char qop[] = "auth";
+ char uri[128];
+ char response[512];
+
+ result = Curl_base64_decode(chlg64, &chlg, &chlglen);
+
+ if(result)
+ return result;
+
+ if(!chlg)
+ return CURLE_LOGIN_DENIED;
+
+ /* Retrieve nonce string from the challenge */
+ if(!sasl_digest_get_key_value(chlg, "nonce=\"", nonce,
+ sizeof(nonce), '\"')) {
+ Curl_safefree(chlg);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Retrieve realm string from the challenge */
+ if(!sasl_digest_get_key_value(chlg, "realm=\"", realm,
+ sizeof(realm), '\"')) {
+ /* Challenge does not have a realm, set empty string [RFC2831] page 6 */
+ strcpy(realm, "");
+ }
+
+ /* Retrieve algorithm string from the challenge */
+ if(!sasl_digest_get_key_value(chlg, "algorithm=", alg, sizeof(alg), ',')) {
+ Curl_safefree(chlg);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ Curl_safefree(chlg);
+
+ /* We do not support other algorithms */
+ if(strcmp(alg, "md5-sess") != 0)
+ return CURLE_LOGIN_DENIED;
+
+ /* Generate 64 bits of random data */
+ for(i = 0; i < 8; i++)
+ 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);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) userp,
+ curlx_uztoui(strlen(userp)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) realm,
+ curlx_uztoui(strlen(realm)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) passwdp,
+ curlx_uztoui(strlen(passwdp)));
+ Curl_MD5_final(ctxt, digest);
+
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) digest, MD5_DIGEST_LEN);
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+ curlx_uztoui(strlen(nonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+ curlx_uztoui(strlen(cnonce)));
+ Curl_MD5_final(ctxt, digest);
+
+ /* Convert calculated 16 octet hex into 32 bytes string */
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&HA1_hex[2 * i], 3, "%02x", digest[i]);
+
+ /* Prepare the URL string */
+ snprintf(uri, sizeof(uri), "%s/%s", service, realm);
+
+ /* Calculate H(A2) */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) method,
+ curlx_uztoui(strlen(method)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) uri,
+ curlx_uztoui(strlen(uri)));
+ Curl_MD5_final(ctxt, digest);
+
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&HA2_hex[2 * i], 3, "%02x", digest[i]);
+
+ /* Now calculate the response hash */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) HA1_hex, 2 * MD5_DIGEST_LEN);
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) nonce,
+ curlx_uztoui(strlen(nonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+ Curl_MD5_update(ctxt, (const unsigned char *) nonceCount,
+ curlx_uztoui(strlen(nonceCount)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) cnonce,
+ curlx_uztoui(strlen(cnonce)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+ Curl_MD5_update(ctxt, (const unsigned char *) qop,
+ curlx_uztoui(strlen(qop)));
+ Curl_MD5_update(ctxt, (const unsigned char *) ":", 1);
+
+ Curl_MD5_update(ctxt, (const unsigned char *) HA2_hex, 2 * MD5_DIGEST_LEN);
+ Curl_MD5_final(ctxt, digest);
+
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&resp_hash_hex[2 * i], 3, "%02x", digest[i]);
+
+ snprintf(response, sizeof(response),
+ "username=\"%s\",realm=\"%s\",nonce=\"%s\","
+ "cnonce=\"%s\",nc=\"%s\",digest-uri=\"%s\",response=%s",
+ userp, realm, nonce,
+ cnonce, nonceCount, uri, resp_hash_hex);
+
+ /* Base64 encode the reply */
+ return Curl_base64_encode(data, response, 0, outptr, outlen);
+}
+#endif
+
+#ifdef USE_NTLM
+/*
+ * Curl_sasl_create_ntlm_type1_message()
+ *
+ * This is used to generate an already encoded NTLM type-1 message ready for
+ * sending to the recipient.
+ *
+ * Note: This is a simple wrapper of the NTLM function which means that any
+ * SASL based protocols don't have to include the NTLM functions directly.
+ *
+ * Parameters:
+ *
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The ntlm data struct being used and modified.
+ * 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_ntlm_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+{
+ return Curl_ntlm_create_type1_message(userp, passwdp, ntlm, outptr,
+ outlen);
+}
+
+/*
+ * Curl_sasl_create_ntlm_type3_message()
+ *
+ * This is used to generate an already encoded NTLM type-3 message ready for
+ * sending to the recipient.
+ *
+ * Parameters:
+ *
+ * data [in] - Pointer to session handle.
+ * header [in] - Pointer to the base64 encoded type-2 message buffer.
+ * userp [in] - The user name in the format User or Domain\User.
+ * passdwp [in] - The user's password.
+ * ntlm [in/out] - The ntlm data struct being used and modified.
+ * 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_ntlm_type3_message(struct SessionHandle *data,
+ const char *header,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen)
+{
+ CURLcode result = Curl_ntlm_decode_type2_message(data, header, ntlm);
+
+ if(!result)
+ result = Curl_ntlm_create_type3_message(data, userp, passwdp, ntlm,
+ outptr, outlen);
+
+ return result;
+}
+#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()
+ *
+ * This is used to cleanup any libraries or curl modules used by the sasl
+ * functions.
+ *
+ * Parameters:
+ *
+ * conn [in] - Pointer to the connection data.
+ * authused [in] - The authentication mechanism used.
+ */
+void Curl_sasl_cleanup(struct connectdata *conn, unsigned int authused)
+{
+#ifdef USE_NTLM
+ /* Cleanup the ntlm structure */
+ if(authused == SASL_MECH_NTLM) {
+ Curl_ntlm_sspi_cleanup(&conn->ntlm);
+ }
+ (void)conn;
+#else
+ /* Reserved for future use */
+ (void)conn;
+ (void)authused;
+#endif
+}
diff --git a/libs/libcurl/src/curl_sasl.h b/libs/libcurl/src/curl_sasl.h
new file mode 100644
index 0000000000..2b6a5a26aa
--- /dev/null
+++ b/libs/libcurl/src/curl_sasl.h
@@ -0,0 +1,115 @@
+#ifndef HEADER_CURL_SASL_H
+#define HEADER_CURL_SASL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 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 "pingpong.h"
+
+/* Authentication mechanism values */
+#define SASL_AUTH_NONE 0
+#define SASL_AUTH_ANY ~0U
+
+/* Authentication mechanism flags */
+#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,
+ const char *userp,
+ const char *passwdp,
+ char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded LOGIN authentication message
+ containing either the user name or password details */
+CURLcode Curl_sasl_create_login_message(struct SessionHandle *data,
+ const char *valuep, char **outptr,
+ size_t *outlen);
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* This is used to generate a base64 encoded CRAM-MD5 response message */
+CURLcode Curl_sasl_create_cram_md5_message(struct SessionHandle *data,
+ const char *chlg64,
+ const char *user,
+ const char *passwdp,
+ char **outptr, size_t *outlen);
+
+/* This is used to generate a base64 encoded DIGEST-MD5 response message */
+CURLcode Curl_sasl_create_digest_md5_message(struct SessionHandle *data,
+ const char *chlg64,
+ const char *user,
+ const char *passwdp,
+ const char *service,
+ char **outptr, size_t *outlen);
+#endif
+
+#ifdef USE_NTLM
+/* This is used to generate a base64 encoded NTLM type-1 message */
+CURLcode Curl_sasl_create_ntlm_type1_message(const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr,
+ size_t *outlen);
+
+/* This is used to decode an incoming NTLM type-2 message and generate a
+ base64 encoded type-3 response */
+CURLcode Curl_sasl_create_ntlm_type3_message(struct SessionHandle *data,
+ const char *header,
+ const char *userp,
+ const char *passwdp,
+ struct ntlmdata *ntlm,
+ char **outptr, size_t *outlen);
+
+#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);
+
+#endif /* HEADER_CURL_SASL_H */
diff --git a/libs/libcurl/src/curl_schannel.c b/libs/libcurl/src/curl_schannel.c
new file mode 100644
index 0000000000..68139db586
--- /dev/null
+++ b/libs/libcurl/src/curl_schannel.c
@@ -0,0 +1,1308 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012 - 2013, Marc Hoersken, <info@marc-hoersken.de>
+ * Copyright (C) 2012, Mark Salisbury, <mark.salisbury@hp.com>
+ * Copyright (C) 2012 - 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all SChannel-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ */
+
+/*
+ * Based upon the PolarSSL implementation in polarssl.c and polarssl.h:
+ * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * Based upon the CyaSSL implementation in cyassl.c and cyassl.h:
+ * Copyright (C) 1998 - 2012, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * Thanks for code and inspiration!
+ */
+
+/*
+ * TODO list for TLS/SSL implementation:
+ * - implement client certificate authentication
+ * - implement custom server certificate validation
+ * - implement cipher/algorithm option
+ *
+ * Related articles on MSDN:
+ * - Getting a Certificate for Schannel
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa375447.aspx
+ * - Specifying Schannel Ciphers and Cipher Strengths
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/aa380161.aspx
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_SCHANNEL
+
+#ifndef USE_WINDOWS_SSPI
+# error "Can't compile SCHANNEL support without SSPI."
+#endif
+
+#include "curl_sspi.h"
+#include "curl_schannel.h"
+#include "sslgen.h"
+#include "sendf.h"
+#include "connect.h" /* for the connect timeout */
+#include "strerror.h"
+#include "select.h" /* for the socket readyness */
+#include "inet_pton.h" /* for IP addr SNI check */
+#include "curl_multibyte.h"
+#include "warnless.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"
+
+/* Uncomment to force verbose output
+ * #define infof(x, y, ...) printf(y, __VA_ARGS__)
+ * #define failf(x, y, ...) printf(y, __VA_ARGS__)
+ */
+
+static Curl_recv schannel_recv;
+static Curl_send schannel_send;
+
+#ifdef _WIN32_WCE
+static CURLcode verify_certificate(struct connectdata *conn, int sockindex);
+#endif
+
+static void InitSecBuffer(SecBuffer *buffer, unsigned long BufType,
+ void *BufDataPtr, unsigned long BufByteSize)
+{
+ buffer->cbBuffer = BufByteSize;
+ buffer->BufferType = BufType;
+ buffer->pvBuffer = BufDataPtr;
+}
+
+static void InitSecBufferDesc(SecBufferDesc *desc, SecBuffer *BufArr,
+ unsigned long NumArrElem)
+{
+ desc->ulVersion = SECBUFFER_VERSION;
+ desc->pBuffers = BufArr;
+ desc->cBuffers = NumArrElem;
+}
+
+static CURLcode
+schannel_connect_step1(struct connectdata *conn, int sockindex)
+{
+ ssize_t written = -1;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SecBuffer outbuf;
+ SecBufferDesc outbuf_desc;
+ SCHANNEL_CRED schannel_cred;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ struct curl_schannel_cred *old_cred = NULL;
+ struct in_addr addr;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr6;
+#endif
+ TCHAR *host_name;
+ CURLcode code;
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 1/3)\n",
+ conn->host.name, conn->remote_port);
+
+ /* check for an existing re-usable credential handle */
+ if(!Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL)) {
+ connssl->cred = old_cred;
+ infof(data, "schannel: re-using existing credential handle\n");
+ }
+ else {
+ /* setup Schannel API options */
+ memset(&schannel_cred, 0, sizeof(schannel_cred));
+ schannel_cred.dwVersion = SCHANNEL_CRED_VERSION;
+
+ if(data->set.ssl.verifypeer) {
+#ifdef _WIN32_WCE
+ /* certificate validation on CE doesn't seem to work right; we'll
+ do it following a more manual process. */
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+ SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+#else
+ schannel_cred.dwFlags = SCH_CRED_AUTO_CRED_VALIDATION |
+ SCH_CRED_REVOCATION_CHECK_CHAIN;
+#endif
+ infof(data, "schannel: checking server certificate revocation\n");
+ }
+ else {
+ schannel_cred.dwFlags = SCH_CRED_MANUAL_CRED_VALIDATION |
+ SCH_CRED_IGNORE_NO_REVOCATION_CHECK |
+ SCH_CRED_IGNORE_REVOCATION_OFFLINE;
+ infof(data, "schannel: disable server certificate revocation checks\n");
+ }
+
+ if(Curl_inet_pton(AF_INET, conn->host.name, &addr)
+#ifdef ENABLE_IPV6
+ || Curl_inet_pton(AF_INET6, conn->host.name, &addr6)
+#endif
+ ) {
+ schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+ infof(data, "schannel: using IP address, SNI is being disabled by "
+ "disabling the servername check against the "
+ "subject names in server certificates.\n");
+ }
+
+ if(!data->set.ssl.verifyhost) {
+ schannel_cred.dwFlags |= SCH_CRED_NO_SERVERNAME_CHECK;
+ infof(data, "schannel: verifyhost setting prevents Schannel from "
+ "comparing the supplied target name with the subject "
+ "names in server certificates. Also disables SNI.\n");
+ }
+
+ switch(data->set.ssl.version) {
+ case CURL_SSLVERSION_TLSv1:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_TLS1_0_CLIENT |
+ SP_PROT_TLS1_1_CLIENT |
+ SP_PROT_TLS1_2_CLIENT;
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ schannel_cred.grbitEnabledProtocols = SP_PROT_SSL2_CLIENT;
+ break;
+ }
+
+ /* allocate memory for the re-usable credential handle */
+ connssl->cred = malloc(sizeof(struct curl_schannel_cred));
+ if(!connssl->cred) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memset(connssl->cred, 0, sizeof(struct curl_schannel_cred));
+
+ /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa374716.aspx */
+ sspi_status = s_pSecFn->AcquireCredentialsHandle(NULL, (TCHAR *)UNISP_NAME,
+ SECPKG_CRED_OUTBOUND, NULL, &schannel_cred, NULL, NULL,
+ &connssl->cred->cred_handle, &connssl->cred->time_stamp);
+
+ if(sspi_status != SEC_E_OK) {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: AcquireCredentialsHandle failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ Curl_safefree(connssl->cred);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* setup output buffer */
+ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+ /* setup request flags */
+ connssl->req_flags = ISC_REQ_SEQUENCE_DETECT | ISC_REQ_REPLAY_DETECT |
+ ISC_REQ_CONFIDENTIALITY | ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_STREAM;
+
+ /* allocate memory for the security context handle */
+ connssl->ctxt = malloc(sizeof(struct curl_schannel_ctxt));
+ if(!connssl->ctxt) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memset(connssl->ctxt, 0, sizeof(struct curl_schannel_ctxt));
+
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle, NULL, host_name,
+ connssl->req_flags, 0, 0, NULL, 0, &connssl->ctxt->ctxt_handle,
+ &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ if(sspi_status != SEC_I_CONTINUE_NEEDED) {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: initial InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ Curl_safefree(connssl->ctxt);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "schannel: sending initial handshake data: "
+ "sending %lu bytes...\n", outbuf.cbBuffer);
+
+ /* send initial handshake data which is now stored in output buffer */
+ code = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+ outbuf.cbBuffer, &written);
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ if((code != CURLE_OK) || (outbuf.cbBuffer != (size_t)written)) {
+ failf(data, "schannel: failed to send initial handshake data: "
+ "sent %zd of %lu bytes", written, outbuf.cbBuffer);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ infof(data, "schannel: sent initial handshake data: "
+ "sent %zd bytes\n", written);
+
+ /* continue to second handshake step */
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step2(struct connectdata *conn, int sockindex)
+{
+ int i;
+ ssize_t nread = -1, written = -1;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SecBuffer outbuf[2];
+ SecBufferDesc outbuf_desc;
+ SecBuffer inbuf[2];
+ SecBufferDesc inbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ TCHAR *host_name;
+ CURLcode code;
+ bool doread;
+
+ doread = (connssl->connecting_state != ssl_connect_2_writing) ? TRUE : FALSE;
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 2/3)\n",
+ conn->host.name, conn->remote_port);
+
+ /* buffer to store previously received and encrypted data */
+ if(connssl->encdata_buffer == NULL) {
+ connssl->encdata_offset = 0;
+ connssl->encdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ connssl->encdata_buffer = malloc(connssl->encdata_length);
+ if(connssl->encdata_buffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* if we need a bigger buffer to read a full message, increase buffer now */
+ if(connssl->encdata_length - connssl->encdata_offset <
+ CURL_SCHANNEL_BUFFER_FREE_SIZE) {
+ /* increase internal encrypted data buffer */
+ connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
+ connssl->encdata_buffer = realloc(connssl->encdata_buffer,
+ connssl->encdata_length);
+
+ if(connssl->encdata_buffer == NULL) {
+ failf(data, "schannel: unable to re-allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ for(;;) {
+ if(doread) {
+ /* read encrypted handshake data from socket */
+ code = Curl_read_plain(conn->sock[sockindex],
+ (char *) (connssl->encdata_buffer + connssl->encdata_offset),
+ connssl->encdata_length - connssl->encdata_offset,
+ &nread);
+ if(code == CURLE_AGAIN) {
+ if(connssl->connecting_state != ssl_connect_2_writing)
+ connssl->connecting_state = ssl_connect_2_reading;
+ infof(data, "schannel: failed to receive handshake, "
+ "need more data\n");
+ return CURLE_OK;
+ }
+ else if((code != CURLE_OK) || (nread == 0)) {
+ failf(data, "schannel: failed to receive handshake, "
+ "SSL/TLS connection failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* increase encrypted data buffer offset */
+ connssl->encdata_offset += nread;
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ /* setup input buffers */
+ InitSecBuffer(&inbuf[0], SECBUFFER_TOKEN, malloc(connssl->encdata_offset),
+ curlx_uztoul(connssl->encdata_offset));
+ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&inbuf_desc, inbuf, 2);
+
+ /* setup output buffers */
+ InitSecBuffer(&outbuf[0], SECBUFFER_TOKEN, NULL, 0);
+ InitSecBuffer(&outbuf[1], SECBUFFER_ALERT, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, outbuf, 2);
+
+ if(inbuf[0].pvBuffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* copy received handshake data into input buffer */
+ memcpy(inbuf[0].pvBuffer, connssl->encdata_buffer,
+ connssl->encdata_offset);
+
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375924.aspx */
+
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle, &connssl->ctxt->ctxt_handle,
+ host_name, connssl->req_flags, 0, 0, &inbuf_desc, 0, NULL,
+ &outbuf_desc, &connssl->ret_flags, &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ /* free buffer for received handshake data */
+ Curl_safefree(inbuf[0].pvBuffer);
+
+ /* check if the handshake was incomplete */
+ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ infof(data, "schannel: received incomplete message, need more data\n");
+ return CURLE_OK;
+ }
+
+ /* check if the handshake needs to be continued */
+ if(sspi_status == SEC_I_CONTINUE_NEEDED || sspi_status == SEC_E_OK) {
+ for(i = 0; i < 2; i++) {
+ /* search for handshake tokens that need to be send */
+ if(outbuf[i].BufferType == SECBUFFER_TOKEN && outbuf[i].cbBuffer > 0) {
+ infof(data, "schannel: sending next handshake data: "
+ "sending %lu bytes...\n", outbuf[i].cbBuffer);
+
+ /* send handshake token to server */
+ code = Curl_write_plain(conn, conn->sock[sockindex],
+ outbuf[i].pvBuffer, outbuf[i].cbBuffer,
+ &written);
+ if((code != CURLE_OK) || (outbuf[i].cbBuffer != (size_t)written)) {
+ failf(data, "schannel: failed to send next handshake data: "
+ "sent %zd of %lu bytes", written, outbuf[i].cbBuffer);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ /* free obsolete buffer */
+ if(outbuf[i].pvBuffer != NULL) {
+ s_pSecFn->FreeContextBuffer(outbuf[i].pvBuffer);
+ }
+ }
+ }
+ else {
+ if(sspi_status == SEC_E_WRONG_PRINCIPAL)
+ failf(data, "schannel: SNI or certificate check failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ else
+ failf(data, "schannel: next InitializeSecurityContext failed: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* check if there was additional remaining encrypted data */
+ if(inbuf[1].BufferType == SECBUFFER_EXTRA && inbuf[1].cbBuffer > 0) {
+ infof(data, "schannel: encrypted data length: %lu\n", inbuf[1].cbBuffer);
+ /*
+ There are two cases where we could be getting extra data here:
+ 1) If we're renegotiating a connection and the handshake is already
+ complete (from the server perspective), it can encrypted app data
+ (not handshake data) in an extra buffer at this point.
+ 2) (sspi_status == SEC_I_CONTINUE_NEEDED) We are negotiating a
+ connection and this extra data is part of the handshake.
+ We should process the data immediately; waiting for the socket to
+ be ready may fail since the server is done sending handshake data.
+ */
+ /* check if the remaining data is less than the total amount
+ and therefore begins after the already processed data */
+ if(connssl->encdata_offset > inbuf[1].cbBuffer) {
+ memmove(connssl->encdata_buffer,
+ (connssl->encdata_buffer + connssl->encdata_offset) -
+ inbuf[1].cbBuffer, inbuf[1].cbBuffer);
+ connssl->encdata_offset = inbuf[1].cbBuffer;
+ if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+ doread = FALSE;
+ continue;
+ }
+ }
+ }
+ else {
+ connssl->encdata_offset = 0;
+ }
+ break;
+ }
+
+ /* check if the handshake needs to be continued */
+ if(sspi_status == SEC_I_CONTINUE_NEEDED) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+
+ /* check if the handshake is complete */
+ if(sspi_status == SEC_E_OK) {
+ connssl->connecting_state = ssl_connect_3;
+ infof(data, "schannel: SSL/TLS handshake complete\n");
+ }
+
+#ifdef _WIN32_WCE
+ /* Windows CE doesn't do any server certificate validation.
+ We have to do it manually. */
+ if(data->set.ssl.verifypeer)
+ return verify_certificate(conn, sockindex);
+#endif
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_step3(struct connectdata *conn, int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct curl_schannel_cred *old_cred = NULL;
+ int incache;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ infof(data, "schannel: SSL/TLS connection with %s port %hu (step 3/3)\n",
+ conn->host.name, conn->remote_port);
+
+ /* check if the required context attributes are met */
+ if(connssl->ret_flags != connssl->req_flags) {
+ if(!(connssl->ret_flags & ISC_RET_SEQUENCE_DETECT))
+ failf(data, "schannel: failed to setup sequence detection");
+ if(!(connssl->ret_flags & ISC_RET_REPLAY_DETECT))
+ failf(data, "schannel: failed to setup replay detection");
+ if(!(connssl->ret_flags & ISC_RET_CONFIDENTIALITY))
+ failf(data, "schannel: failed to setup confidentiality");
+ if(!(connssl->ret_flags & ISC_RET_ALLOCATED_MEMORY))
+ failf(data, "schannel: failed to setup memory allocation");
+ if(!(connssl->ret_flags & ISC_RET_STREAM))
+ failf(data, "schannel: failed to setup stream orientation");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* increment the reference counter of the credential/session handle */
+ if(connssl->cred && connssl->ctxt) {
+ connssl->cred->refcount++;
+ infof(data, "schannel: incremented credential handle refcount = %d\n",
+ connssl->cred->refcount);
+ }
+
+ /* save the current session data for possible re-use */
+ incache = !(Curl_ssl_getsessionid(conn, (void**)&old_cred, NULL));
+ if(incache) {
+ if(old_cred != connssl->cred) {
+ infof(data, "schannel: old credential handle is stale, removing\n");
+ Curl_ssl_delsessionid(conn, (void*)old_cred);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ retcode = Curl_ssl_addsessionid(conn, (void*)connssl->cred,
+ sizeof(struct curl_schannel_cred));
+ if(retcode) {
+ failf(data, "schannel: failed to store credential handle");
+ return retcode;
+ }
+ else {
+ connssl->cred->cached = TRUE;
+ infof(data, "schannel: stored credential handle in session cache\n");
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+schannel_connect_common(struct connectdata *conn, int sockindex,
+ bool nonblocking, bool *done)
+{
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1 == connssl->connecting_state) {
+ /* check out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ retcode = schannel_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* check out how much more time we're allowed */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading ==
+ connssl->connecting_state ? sockfd : CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd, nonblocking ? 0 : timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL/TLS socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL/TLS connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ retcode = schannel_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3 == connssl->connecting_state) {
+ retcode = schannel_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done == connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = schannel_recv;
+ conn->send[sockindex] = schannel_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* reset our connection state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+static ssize_t
+schannel_send(struct connectdata *conn, int sockindex,
+ const void *buf, size_t len, CURLcode *err)
+{
+ ssize_t written = -1;
+ size_t data_len = 0;
+ unsigned char *data = NULL;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ SecBuffer outbuf[4];
+ SecBufferDesc outbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+ CURLcode code;
+
+ /* check if the maximum stream sizes were queried */
+ if(connssl->stream_sizes.cbMaximumMessage == 0) {
+ sspi_status = s_pSecFn->QueryContextAttributes(
+ &connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_STREAM_SIZES,
+ &connssl->stream_sizes);
+ if(sspi_status != SEC_E_OK) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+ }
+
+ /* check if the buffer is longer than the maximum message length */
+ if(len > connssl->stream_sizes.cbMaximumMessage) {
+ *err = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ /* calculate the complete message length and allocate a buffer for it */
+ data_len = connssl->stream_sizes.cbHeader + len +
+ connssl->stream_sizes.cbTrailer;
+ data = (unsigned char*) malloc(data_len);
+ if(data == NULL) {
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+
+ /* setup output buffers (header, data, trailer, empty) */
+ InitSecBuffer(&outbuf[0], SECBUFFER_STREAM_HEADER,
+ data, connssl->stream_sizes.cbHeader);
+ InitSecBuffer(&outbuf[1], SECBUFFER_DATA,
+ data + connssl->stream_sizes.cbHeader, curlx_uztoul(len));
+ InitSecBuffer(&outbuf[2], SECBUFFER_STREAM_TRAILER,
+ data + connssl->stream_sizes.cbHeader + len,
+ connssl->stream_sizes.cbTrailer);
+ InitSecBuffer(&outbuf[3], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, outbuf, 4);
+
+ /* copy data into output buffer */
+ memcpy(outbuf[1].pvBuffer, buf, len);
+
+ /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375390.aspx */
+ sspi_status = s_pSecFn->EncryptMessage(&connssl->ctxt->ctxt_handle, 0,
+ &outbuf_desc, 0);
+
+ /* check if the message was encrypted */
+ if(sspi_status == SEC_E_OK) {
+ written = 0;
+
+ /* send the encrypted message including header, data and trailer */
+ len = outbuf[0].cbBuffer + outbuf[1].cbBuffer + outbuf[2].cbBuffer;
+
+ /*
+ It's important to send the full message which includes the header,
+ encrypted payload, and trailer. Until the client receives all the
+ data a coherent message has not been delivered and the client
+ can't read any of it.
+
+ If we wanted to buffer the unwritten encrypted bytes, we would
+ tell the client that all data it has requested to be sent has been
+ sent. The unwritten encrypted bytes would be the first bytes to
+ send on the next invocation.
+ Here's the catch with this - if we tell the client that all the
+ bytes have been sent, will the client call this method again to
+ send the buffered data? Looking at who calls this function, it
+ seems the answer is NO.
+ */
+
+ /* send entire message or fail */
+ while(len > (size_t)written) {
+ ssize_t this_write;
+ long timeleft;
+ int what;
+
+ this_write = 0;
+
+ timeleft = Curl_timeleft(conn->data, NULL, TRUE);
+ if(timeleft < 0) {
+ /* we already got the timeout */
+ failf(conn->data, "schannel: timed out sending data "
+ "(bytes sent: %zd)", written);
+ *err = CURLE_OPERATION_TIMEDOUT;
+ written = -1;
+ break;
+ }
+
+ what = Curl_socket_ready(CURL_SOCKET_BAD, conn->sock[sockindex],
+ timeleft);
+ if(what < 0) {
+ /* fatal error */
+ failf(conn->data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ *err = CURLE_SEND_ERROR;
+ written = -1;
+ break;
+ }
+ else if(0 == what) {
+ failf(conn->data, "schannel: timed out sending data "
+ "(bytes sent: %zd)", written);
+ *err = CURLE_OPERATION_TIMEDOUT;
+ written = -1;
+ break;
+ }
+ /* socket is writable */
+
+ code = Curl_write_plain(conn, conn->sock[sockindex], data + written,
+ len - written, &this_write);
+ if(code == CURLE_AGAIN)
+ continue;
+ else if(code != CURLE_OK) {
+ *err = code;
+ written = -1;
+ break;
+ }
+
+ written += this_write;
+ }
+ }
+ else if(sspi_status == SEC_E_INSUFFICIENT_MEMORY) {
+ *err = CURLE_OUT_OF_MEMORY;
+ }
+ else{
+ *err = CURLE_SEND_ERROR;
+ }
+
+ Curl_safefree(data);
+
+ if(len == (size_t)written)
+ /* Encrypted message including header, data and trailer entirely sent.
+ The return value is the number of unencrypted bytes that were sent. */
+ written = outbuf[1].cbBuffer;
+
+ return written;
+}
+
+static ssize_t
+schannel_recv(struct connectdata *conn, int sockindex,
+ char *buf, size_t len, CURLcode *err)
+{
+ size_t size = 0;
+ ssize_t nread = 0, ret = -1;
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ bool done = FALSE;
+ SecBuffer inbuf[4];
+ SecBufferDesc inbuf_desc;
+ SECURITY_STATUS sspi_status = SEC_E_OK;
+
+ infof(data, "schannel: client wants to read %zu bytes\n", len);
+ *err = CURLE_OK;
+
+ /* buffer to store previously received and decrypted data */
+ if(connssl->decdata_buffer == NULL) {
+ connssl->decdata_offset = 0;
+ connssl->decdata_length = CURL_SCHANNEL_BUFFER_INIT_SIZE;
+ connssl->decdata_buffer = malloc(connssl->decdata_length);
+ if(connssl->decdata_buffer == NULL) {
+ failf(data, "schannel: unable to allocate memory");
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+ }
+
+ /* increase buffer in order to fit the requested amount of data */
+ while(connssl->encdata_length - connssl->encdata_offset <
+ CURL_SCHANNEL_BUFFER_FREE_SIZE || connssl->encdata_length < len) {
+ /* increase internal encrypted data buffer */
+ connssl->encdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
+ connssl->encdata_buffer = realloc(connssl->encdata_buffer,
+ connssl->encdata_length);
+
+ if(connssl->encdata_buffer == NULL) {
+ failf(data, "schannel: unable to re-allocate memory");
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+ }
+
+ /* read encrypted data from socket */
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+ size = connssl->encdata_length - connssl->encdata_offset;
+ if(size > 0) {
+ *err = Curl_read_plain(conn->sock[sockindex],
+ (char *) (connssl->encdata_buffer + connssl->encdata_offset),
+ size, &nread);
+ /* check for received data */
+ if(*err != CURLE_OK)
+ ret = -1;
+ else {
+ if(nread > 0)
+ /* increase encrypted data buffer offset */
+ connssl->encdata_offset += nread;
+ ret = nread;
+ }
+ infof(data, "schannel: encrypted data got %zd\n", ret);
+ }
+
+ infof(data, "schannel: encrypted data buffer: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+
+ /* check if we still have some data in our buffers */
+ while(connssl->encdata_offset > 0 && sspi_status == SEC_E_OK &&
+ connssl->decdata_offset < len) {
+ /* prepare data buffer for DecryptMessage call */
+ InitSecBuffer(&inbuf[0], SECBUFFER_DATA, connssl->encdata_buffer,
+ curlx_uztoul(connssl->encdata_offset));
+
+ /* we need 3 more empty input buffers for possible output */
+ InitSecBuffer(&inbuf[1], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBuffer(&inbuf[2], SECBUFFER_EMPTY, NULL, 0);
+ InitSecBuffer(&inbuf[3], SECBUFFER_EMPTY, NULL, 0);
+
+ InitSecBufferDesc(&inbuf_desc, inbuf, 4);
+
+ /* http://msdn.microsoft.com/en-us/library/windows/desktop/aa375348.aspx */
+ sspi_status = s_pSecFn->DecryptMessage(&connssl->ctxt->ctxt_handle,
+ &inbuf_desc, 0, NULL);
+
+ /* check if we need more data */
+ if(sspi_status == SEC_E_INCOMPLETE_MESSAGE) {
+ infof(data, "schannel: failed to decrypt data, need more data\n");
+ *err = CURLE_AGAIN;
+ return -1;
+ }
+
+ /* check if everything went fine (server may want to renegotiate
+ context) */
+ if(sspi_status == SEC_E_OK || sspi_status == SEC_I_RENEGOTIATE ||
+ sspi_status == SEC_I_CONTEXT_EXPIRED) {
+ /* check for successfully decrypted data */
+ if(inbuf[1].BufferType == SECBUFFER_DATA) {
+ infof(data, "schannel: decrypted data length: %lu\n",
+ inbuf[1].cbBuffer);
+
+ /* increase buffer in order to fit the received amount of data */
+ size = inbuf[1].cbBuffer > CURL_SCHANNEL_BUFFER_FREE_SIZE ?
+ inbuf[1].cbBuffer : CURL_SCHANNEL_BUFFER_FREE_SIZE;
+ while(connssl->decdata_length - connssl->decdata_offset < size ||
+ connssl->decdata_length < len) {
+ /* increase internal decrypted data buffer */
+ connssl->decdata_length *= CURL_SCHANNEL_BUFFER_STEP_FACTOR;
+ connssl->decdata_buffer = realloc(connssl->decdata_buffer,
+ connssl->decdata_length);
+
+ if(connssl->decdata_buffer == NULL) {
+ failf(data, "schannel: unable to re-allocate memory");
+ *err = CURLE_OUT_OF_MEMORY;
+ return -1;
+ }
+ }
+
+ /* copy decrypted data to internal buffer */
+ size = inbuf[1].cbBuffer;
+ if(size > 0) {
+ memcpy(connssl->decdata_buffer + connssl->decdata_offset,
+ inbuf[1].pvBuffer, size);
+ connssl->decdata_offset += size;
+ }
+
+ infof(data, "schannel: decrypted data added: %zu\n", size);
+ infof(data, "schannel: decrypted data cached: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+ }
+
+ /* check for remaining encrypted data */
+ if(inbuf[3].BufferType == SECBUFFER_EXTRA && inbuf[3].cbBuffer > 0) {
+ infof(data, "schannel: encrypted data length: %lu\n",
+ inbuf[3].cbBuffer);
+
+ /* check if the remaining data is less than the total amount
+ * and therefore begins after the already processed data
+ */
+ if(connssl->encdata_offset > inbuf[3].cbBuffer) {
+ /* move remaining encrypted data forward to the beginning of
+ buffer */
+ memmove(connssl->encdata_buffer,
+ (connssl->encdata_buffer + connssl->encdata_offset) -
+ inbuf[3].cbBuffer, inbuf[3].cbBuffer);
+ connssl->encdata_offset = inbuf[3].cbBuffer;
+ }
+
+ infof(data, "schannel: encrypted data cached: offset %zu length %zu\n",
+ connssl->encdata_offset, connssl->encdata_length);
+ }
+ else{
+ /* reset encrypted buffer offset, because there is no data remaining */
+ connssl->encdata_offset = 0;
+ }
+ }
+
+ /* check if server wants to renegotiate the connection context */
+ if(sspi_status == SEC_I_RENEGOTIATE) {
+ infof(data, "schannel: remote party requests SSL/TLS renegotiation\n");
+
+ /* begin renegotiation */
+ infof(data, "schannel: renegotiating SSL/TLS connection\n");
+ connssl->state = ssl_connection_negotiating;
+ connssl->connecting_state = ssl_connect_2_writing;
+ retcode = schannel_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ *err = retcode;
+ else {
+ infof(data, "schannel: SSL/TLS connection renegotiated\n");
+ /* now retry receiving data */
+ return schannel_recv(conn, sockindex, buf, len, err);
+ }
+ }
+ }
+
+ infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+
+ /* copy requested decrypted data to supplied buffer */
+ size = len < connssl->decdata_offset ? len : connssl->decdata_offset;
+ if(size > 0) {
+ memcpy(buf, connssl->decdata_buffer, size);
+ ret = size;
+
+ /* move remaining decrypted data forward to the beginning of buffer */
+ memmove(connssl->decdata_buffer, connssl->decdata_buffer + size,
+ connssl->decdata_offset - size);
+ connssl->decdata_offset -= size;
+
+ infof(data, "schannel: decrypted data returned %zd\n", size);
+ infof(data, "schannel: decrypted data buffer: offset %zu length %zu\n",
+ connssl->decdata_offset, connssl->decdata_length);
+ }
+
+ /* check if the server closed the connection */
+ if(ret <= 0 && ( /* special check for Windows 2000 Professional */
+ sspi_status == SEC_I_CONTEXT_EXPIRED || (sspi_status == SEC_E_OK &&
+ connssl->encdata_offset > 0 && connssl->encdata_buffer[0] == 0x15))) {
+ infof(data, "schannel: server closed the connection\n");
+ *err = CURLE_OK;
+ return 0;
+ }
+
+ /* check if something went wrong and we need to return an error */
+ if(ret < 0 && sspi_status != SEC_E_OK) {
+ infof(data, "schannel: failed to read data from server: %s\n",
+ Curl_sspi_strerror(conn, sspi_status));
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ return ret;
+}
+
+CURLcode
+Curl_schannel_connect_nonblocking(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ return schannel_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_schannel_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = schannel_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex)
+{
+ const struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->use) /* SSL/TLS is in use */
+ return (connssl->encdata_offset > 0 ||
+ connssl->decdata_offset > 0 ) ? TRUE : FALSE;
+ else
+ return FALSE;
+}
+
+void Curl_schannel_close(struct connectdata *conn, int sockindex)
+{
+ if(conn->ssl[sockindex].use)
+ /* if the SSL/TLS channel hasn't been shut down yet, do that now. */
+ Curl_ssl_shutdown(conn, sockindex);
+}
+
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex)
+{
+ /* See http://msdn.microsoft.com/en-us/library/windows/desktop/aa380138.aspx
+ * Shutting Down an Schannel Connection
+ */
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ infof(data, "schannel: shutting down SSL/TLS connection with %s port %hu\n",
+ conn->host.name, conn->remote_port);
+
+ if(connssl->cred && connssl->ctxt) {
+ SecBufferDesc BuffDesc;
+ SecBuffer Buffer;
+ SECURITY_STATUS sspi_status;
+ SecBuffer outbuf;
+ SecBufferDesc outbuf_desc;
+ CURLcode code;
+ TCHAR *host_name;
+ DWORD dwshut = SCHANNEL_SHUTDOWN;
+
+ InitSecBuffer(&Buffer, SECBUFFER_TOKEN, &dwshut, sizeof(dwshut));
+ InitSecBufferDesc(&BuffDesc, &Buffer, 1);
+
+ sspi_status = s_pSecFn->ApplyControlToken(&connssl->ctxt->ctxt_handle,
+ &BuffDesc);
+
+ if(sspi_status != SEC_E_OK)
+ failf(data, "schannel: ApplyControlToken failure: %s",
+ Curl_sspi_strerror(conn, sspi_status));
+
+ host_name = Curl_convert_UTF8_to_tchar(conn->host.name);
+ if(!host_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* setup output buffer */
+ InitSecBuffer(&outbuf, SECBUFFER_EMPTY, NULL, 0);
+ InitSecBufferDesc(&outbuf_desc, &outbuf, 1);
+
+ sspi_status = s_pSecFn->InitializeSecurityContext(
+ &connssl->cred->cred_handle,
+ &connssl->ctxt->ctxt_handle,
+ host_name,
+ connssl->req_flags,
+ 0,
+ 0,
+ NULL,
+ 0,
+ &connssl->ctxt->ctxt_handle,
+ &outbuf_desc,
+ &connssl->ret_flags,
+ &connssl->ctxt->time_stamp);
+
+ Curl_unicodefree(host_name);
+
+ if((sspi_status == SEC_E_OK) || (sspi_status == SEC_I_CONTEXT_EXPIRED)) {
+ /* send close message which is in output buffer */
+ ssize_t written;
+ code = Curl_write_plain(conn, conn->sock[sockindex], outbuf.pvBuffer,
+ outbuf.cbBuffer, &written);
+
+ s_pSecFn->FreeContextBuffer(outbuf.pvBuffer);
+ if((code != CURLE_OK) || (outbuf.cbBuffer != (size_t)written)) {
+ infof(data, "schannel: failed to send close msg: %s"
+ " (bytes written: %zd)\n", curl_easy_strerror(code), written);
+ }
+ }
+
+ /* free SSPI Schannel API security context handle */
+ if(connssl->ctxt) {
+ infof(data, "schannel: clear security context handle\n");
+ s_pSecFn->DeleteSecurityContext(&connssl->ctxt->ctxt_handle);
+ Curl_safefree(connssl->ctxt);
+ }
+
+ /* free SSPI Schannel API credential handle */
+ if(connssl->cred) {
+ /* decrement the reference counter of the credential/session handle */
+ if(connssl->cred->refcount > 0) {
+ connssl->cred->refcount--;
+ infof(data, "schannel: decremented credential handle refcount = %d\n",
+ connssl->cred->refcount);
+ }
+
+ /* 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) {
+ Curl_safefree(connssl->encdata_buffer);
+ connssl->encdata_length = 0;
+ connssl->encdata_offset = 0;
+ }
+
+ /* free internal buffer for received decrypted data */
+ if(connssl->decdata_buffer != NULL) {
+ Curl_safefree(connssl->decdata_buffer);
+ connssl->decdata_length = 0;
+ connssl->decdata_offset = 0;
+ }
+
+ return CURLE_OK;
+}
+
+void Curl_schannel_session_free(void *ptr)
+{
+ struct curl_schannel_cred *cred = ptr;
+
+ if(cred && cred->cached && cred->refcount == 0) {
+ s_pSecFn->FreeCredentialsHandle(&cred->cred_handle);
+ Curl_safefree(cred);
+ }
+}
+
+int Curl_schannel_init(void)
+{
+ return (Curl_sspi_global_init() == CURLE_OK ? 1 : 0);
+}
+
+void Curl_schannel_cleanup(void)
+{
+ Curl_sspi_global_cleanup();
+}
+
+size_t Curl_schannel_version(char *buffer, size_t size)
+{
+ size = snprintf(buffer, size, "WinSSL");
+
+ return size;
+}
+
+#ifdef _WIN32_WCE
+static CURLcode verify_certificate(struct connectdata *conn, int sockindex)
+{
+ SECURITY_STATUS status;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode result = CURLE_OK;
+ CERT_CONTEXT *pCertContextServer = NULL;
+ const CERT_CHAIN_CONTEXT *pChainContext = NULL;
+
+ status = s_pSecFn->QueryContextAttributes(&connssl->ctxt->ctxt_handle,
+ SECPKG_ATTR_REMOTE_CERT_CONTEXT,
+ &pCertContextServer);
+
+ if((status != SEC_E_OK) || (pCertContextServer == NULL)) {
+ failf(data, "schannel: Failed to read remote certificate context: %s",
+ Curl_sspi_strerror(conn, status));
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK) {
+ CERT_CHAIN_PARA ChainPara;
+ memset(&ChainPara, 0, sizeof(ChainPara));
+ ChainPara.cbSize = sizeof(ChainPara);
+
+ if(!CertGetCertificateChain(NULL,
+ pCertContextServer,
+ NULL,
+ pCertContextServer->hCertStore,
+ &ChainPara,
+ 0,
+ NULL,
+ &pChainContext)) {
+ failf(data, "schannel: CertGetCertificateChain failed: %s",
+ Curl_sspi_strerror(conn, GetLastError()));
+ pChainContext = NULL;
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ if(result == CURLE_OK) {
+ CERT_SIMPLE_CHAIN *pSimpleChain = pChainContext->rgpChain[0];
+ DWORD dwTrustErrorMask = ~(DWORD)(CERT_TRUST_IS_NOT_TIME_NESTED|
+ CERT_TRUST_REVOCATION_STATUS_UNKNOWN);
+ dwTrustErrorMask &= pSimpleChain->TrustStatus.dwErrorStatus;
+ if(dwTrustErrorMask) {
+ if(dwTrustErrorMask & CERT_TRUST_IS_PARTIAL_CHAIN)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_PARTIAL_CHAIN");
+ if(dwTrustErrorMask & CERT_TRUST_IS_UNTRUSTED_ROOT)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_UNTRUSTED_ROOT");
+ if(dwTrustErrorMask & CERT_TRUST_IS_NOT_TIME_VALID)
+ failf(data, "schannel: CertGetCertificateChain trust error"
+ " CERT_TRUST_IS_NOT_TIME_VALID");
+ failf(data, "schannel: CertGetCertificateChain error mask: 0x%08x",
+ dwTrustErrorMask);
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(result == CURLE_OK) {
+ if(data->set.ssl.verifyhost) {
+ TCHAR cert_hostname_buff[128];
+ xcharp_u hostname;
+ xcharp_u cert_hostname;
+ DWORD len;
+
+ cert_hostname.const_tchar_ptr = cert_hostname_buff;
+ hostname.tchar_ptr = Curl_convert_UTF8_to_tchar(conn->host.name);
+
+ len = CertGetNameString(pCertContextServer,
+ CERT_NAME_DNS_TYPE,
+ 0,
+ NULL,
+ cert_hostname.tchar_ptr,
+ 128);
+ if(len > 0 && *cert_hostname.tchar_ptr == '*') {
+ /* this is a wildcard cert. try matching the last len - 1 chars */
+ int hostname_len = strlen(conn->host.name);
+ cert_hostname.tchar_ptr++;
+ if(_tcsicmp(cert_hostname.const_tchar_ptr,
+ hostname.const_tchar_ptr + hostname_len - len + 2) != 0)
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else if(len == 0 || _tcsicmp(hostname.const_tchar_ptr,
+ cert_hostname.const_tchar_ptr) != 0) {
+ result = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ if(result == CURLE_PEER_FAILED_VERIFICATION) {
+ char *_cert_hostname;
+ _cert_hostname = Curl_convert_tchar_to_UTF8(cert_hostname.tchar_ptr);
+ failf(data, "schannel: CertGetNameString() certificate hostname "
+ "(%s) did not match connection (%s)",
+ _cert_hostname, conn->host.name);
+ Curl_unicodefree(_cert_hostname);
+ }
+ Curl_unicodefree(hostname.tchar_ptr);
+ }
+ }
+
+ if(pChainContext)
+ CertFreeCertificateChain(pChainContext);
+
+ if(pCertContextServer)
+ CertFreeCertificateContext(pCertContextServer);
+
+ return result;
+}
+#endif /* _WIN32_WCE */
+
+#endif /* USE_SCHANNEL */
diff --git a/libs/libcurl/src/curl_schannel.h b/libs/libcurl/src/curl_schannel.h
new file mode 100644
index 0000000000..b82c734a0a
--- /dev/null
+++ b/libs/libcurl/src/curl_schannel.h
@@ -0,0 +1,132 @@
+#ifndef HEADER_CURL_SCHANNEL_H
+#define HEADER_CURL_SCHANNEL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2012, Marc Hoersken, <info@marc-hoersken.de>, et al.
+ * Copyright (C) 2012, 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_SCHANNEL
+
+#include "urldata.h"
+
+#ifndef UNISP_NAME_A
+#define UNISP_NAME_A "Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME_W
+#define UNISP_NAME_W L"Microsoft Unified Security Protocol Provider"
+#endif
+
+#ifndef UNISP_NAME
+#ifdef UNICODE
+#define UNISP_NAME UNISP_NAME_W
+#else
+#define UNISP_NAME UNISP_NAME_A
+#endif
+#endif
+
+#ifndef SP_PROT_SSL2_CLIENT
+#define SP_PROT_SSL2_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_SSL3_CLIENT
+#define SP_PROT_SSL3_CLIENT 0x00000008
+#endif
+
+#ifndef SP_PROT_TLS1_CLIENT
+#define SP_PROT_TLS1_CLIENT 0x00000080
+#endif
+
+#ifndef SP_PROT_TLS1_0_CLIENT
+#define SP_PROT_TLS1_0_CLIENT SP_PROT_TLS1_CLIENT
+#endif
+
+#ifndef SP_PROT_TLS1_1_CLIENT
+#define SP_PROT_TLS1_1_CLIENT 0x00000200
+#endif
+
+#ifndef SP_PROT_TLS1_2_CLIENT
+#define SP_PROT_TLS1_2_CLIENT 0x00000800
+#endif
+
+#ifndef SECBUFFER_ALERT
+#define SECBUFFER_ALERT 17
+#endif
+
+#ifndef ISC_RET_REPLAY_DETECT
+#define ISC_RET_REPLAY_DETECT 0x00000004
+#endif
+
+#ifndef ISC_RET_SEQUENCE_DETECT
+#define ISC_RET_SEQUENCE_DETECT 0x00000008
+#endif
+
+#ifndef ISC_RET_CONFIDENTIALITY
+#define ISC_RET_CONFIDENTIALITY 0x00000010
+#endif
+
+#ifndef ISC_RET_ALLOCATED_MEMORY
+#define ISC_RET_ALLOCATED_MEMORY 0x00000100
+#endif
+
+#ifndef ISC_RET_STREAM
+#define ISC_RET_STREAM 0x00008000
+#endif
+
+
+#define CURL_SCHANNEL_BUFFER_INIT_SIZE 4096
+#define CURL_SCHANNEL_BUFFER_FREE_SIZE 1024
+#define CURL_SCHANNEL_BUFFER_STEP_FACTOR 2
+
+
+CURLcode Curl_schannel_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_schannel_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+bool Curl_schannel_data_pending(const struct connectdata *conn, int sockindex);
+void Curl_schannel_close(struct connectdata *conn, int sockindex);
+int Curl_schannel_shutdown(struct connectdata *conn, int sockindex);
+void Curl_schannel_session_free(void *ptr);
+
+int Curl_schannel_init(void);
+void Curl_schannel_cleanup(void);
+size_t Curl_schannel_version(char *buffer, size_t size);
+
+/* API setup for Schannel */
+#define curlssl_init Curl_schannel_init
+#define curlssl_cleanup Curl_schannel_cleanup
+#define curlssl_connect Curl_schannel_connect
+#define curlssl_connect_nonblocking Curl_schannel_connect_nonblocking
+#define curlssl_session_free Curl_schannel_session_free
+#define curlssl_close_all(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_close Curl_schannel_close
+#define curlssl_shutdown Curl_schannel_shutdown
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_schannel_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending Curl_schannel_data_pending
+#endif /* USE_SCHANNEL */
+#endif /* HEADER_CURL_SCHANNEL_H */
diff --git a/libs/libcurl/src/curl_sec.h b/libs/libcurl/src/curl_sec.h
new file mode 100644
index 0000000000..82151e9c78
--- /dev/null
+++ b/libs/libcurl/src/curl_sec.h
@@ -0,0 +1,51 @@
+#ifndef HEADER_CURL_SECURITY_H
+#define HEADER_CURL_SECURITY_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.
+ *
+ ***************************************************************************/
+
+struct Curl_sec_client_mech {
+ const char *name;
+ size_t size;
+ int (*init)(void *);
+ int (*auth)(void *, struct connectdata *);
+ void (*end)(void *);
+ int (*check_prot)(void *, int);
+ int (*overhead)(void *, int, int);
+ int (*encode)(void *, const void*, int, int, void**, struct connectdata *);
+ int (*decode)(void *, void*, int, int, struct connectdata *);
+};
+
+#define AUTH_OK 0
+#define AUTH_CONTINUE 1
+#define AUTH_ERROR 2
+
+#ifdef HAVE_GSSAPI
+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);
+
+extern struct Curl_sec_client_mech Curl_krb5_client_mech;
+#endif
+
+#endif /* HEADER_CURL_SECURITY_H */
diff --git a/libs/libcurl/src/curl_setup.h b/libs/libcurl/src/curl_setup.h
new file mode 100644
index 0000000000..7edeca2123
--- /dev/null
+++ b/libs/libcurl/src/curl_setup.h
@@ -0,0 +1,707 @@
+#ifndef HEADER_CURL_SETUP_H
+#define HEADER_CURL_SETUP_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.
+ *
+ ***************************************************************************/
+
+/*
+ * Define WIN32 when build target is Win32 API
+ */
+
+#if (defined(_WIN32) || defined(__WIN32__)) && !defined(WIN32) && \
+ !defined(__SYMBIAN32__)
+#define WIN32
+#endif
+
+/*
+ * Include configuration script results or hand-crafted
+ * configuration file for platforms which lack config tool.
+ */
+
+#ifdef HAVE_CONFIG_H
+
+#include "curl_config.h"
+
+#else /* HAVE_CONFIG_H */
+
+#ifdef _WIN32_WCE
+# include "config-win32ce.h"
+#else
+# ifdef WIN32
+# include "config-win32.h"
+# endif
+#endif
+
+#if defined(macintosh) && defined(__MRC__)
+# include "config-mac.h"
+#endif
+
+#ifdef __riscos__
+# include "config-riscos.h"
+#endif
+
+#ifdef __AMIGA__
+# include "config-amigaos.h"
+#endif
+
+#ifdef __SYMBIAN32__
+# include "config-symbian.h"
+#endif
+
+#ifdef __OS400__
+# include "config-os400.h"
+#endif
+
+#ifdef TPF
+# include "config-tpf.h"
+#endif
+
+#ifdef __VXWORKS__
+# include "config-vxworks.h"
+#endif
+
+#endif /* HAVE_CONFIG_H */
+
+/* ================================================================ */
+/* Definition of preprocessor macros/symbols which modify compiler */
+/* behavior or generated code characteristics must be done here, */
+/* as appropriate, before any system header file is included. It is */
+/* also possible to have them defined in the config file included */
+/* before this point. As a result of all this we frown inclusion of */
+/* system header files in our config files, avoid this at any cost. */
+/* ================================================================ */
+
+/*
+ * AIX 4.3 and newer needs _THREAD_SAFE defined to build
+ * proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_THREAD_SAFE
+# ifndef _THREAD_SAFE
+# define _THREAD_SAFE
+# endif
+#endif
+
+/*
+ * Tru64 needs _REENTRANT set for a few function prototypes and
+ * things to appear in the system header files. Unixware needs it
+ * to build proper reentrant code. Others may also need it.
+ */
+
+#ifdef NEED_REENTRANT
+# ifndef _REENTRANT
+# define _REENTRANT
+# endif
+#endif
+
+/* ================================================================ */
+/* If you need to include a system header file for your platform, */
+/* please, do it beyond the point further indicated in this file. */
+/* ================================================================ */
+
+/*
+ * libcurl's external interface definitions are also used internally,
+ * and might also include required system header files to define them.
+ */
+
+#include <curl/curlbuild.h>
+
+/*
+ * Compile time sanity checks must also be done when building the library.
+ */
+
+#include <curl/curlrules.h>
+
+/*
+ * Ensure that no one is using the old SIZEOF_CURL_OFF_T macro
+ */
+
+#ifdef SIZEOF_CURL_OFF_T
+# error "SIZEOF_CURL_OFF_T shall not be defined!"
+ Error Compilation_aborted_SIZEOF_CURL_OFF_T_shall_not_be_defined
+#endif
+
+/*
+ * Set up internal curl_off_t formatting string directives for
+ * exclusive use with libcurl's internal *printf functions.
+ */
+
+#ifdef FORMAT_OFF_T
+# error "FORMAT_OFF_T shall not be defined before this point!"
+ Error Compilation_aborted_FORMAT_OFF_T_already_defined
+#endif
+
+#ifdef FORMAT_OFF_TU
+# error "FORMAT_OFF_TU shall not be defined before this point!"
+ Error Compilation_aborted_FORMAT_OFF_TU_already_defined
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+# define FORMAT_OFF_T "lld"
+# define FORMAT_OFF_TU "llu"
+#else
+# define FORMAT_OFF_T "ld"
+# define FORMAT_OFF_TU "lu"
+#endif
+
+/*
+ * Disable other protocols when http is the only one desired.
+ */
+
+#ifdef HTTP_ONLY
+# ifndef CURL_DISABLE_TFTP
+# define CURL_DISABLE_TFTP
+# endif
+# ifndef CURL_DISABLE_FTP
+# define CURL_DISABLE_FTP
+# endif
+# ifndef CURL_DISABLE_LDAP
+# define CURL_DISABLE_LDAP
+# endif
+# ifndef CURL_DISABLE_TELNET
+# define CURL_DISABLE_TELNET
+# endif
+# ifndef CURL_DISABLE_DICT
+# define CURL_DISABLE_DICT
+# endif
+# ifndef CURL_DISABLE_FILE
+# define CURL_DISABLE_FILE
+# endif
+# ifndef CURL_DISABLE_RTSP
+# define CURL_DISABLE_RTSP
+# endif
+# ifndef CURL_DISABLE_POP3
+# define CURL_DISABLE_POP3
+# endif
+# ifndef CURL_DISABLE_IMAP
+# define CURL_DISABLE_IMAP
+# endif
+# ifndef CURL_DISABLE_SMTP
+# define CURL_DISABLE_SMTP
+# endif
+# ifndef CURL_DISABLE_RTSP
+# define CURL_DISABLE_RTSP
+# endif
+# ifndef CURL_DISABLE_RTMP
+# define CURL_DISABLE_RTMP
+# endif
+# ifndef CURL_DISABLE_GOPHER
+# define CURL_DISABLE_GOPHER
+# endif
+#endif
+
+/*
+ * When http is disabled rtsp is not supported.
+ */
+
+#if defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_RTSP)
+# define CURL_DISABLE_RTSP
+#endif
+
+/* ================================================================ */
+/* No system header file shall be included in this file before this */
+/* point. The only allowed ones are those included from curlbuild.h */
+/* ================================================================ */
+
+/*
+ * OS/400 setup file includes some system headers.
+ */
+
+#ifdef __OS400__
+# include "setup-os400.h"
+#endif
+
+/*
+ * VMS setup file includes some system headers.
+ */
+
+#ifdef __VMS
+# include "setup-vms.h"
+#endif
+
+/*
+ * Include header files for windows builds before redefining anything.
+ * Use this preprocessor block only to include or exclude windows.h,
+ * winsock2.h, ws2tcpip.h or winsock.h. Any other windows thing belongs
+ * to any other further and independent block. Under Cygwin things work
+ * just as under linux (e.g. <sys/socket.h>) and the winsock headers should
+ * never be included when __CYGWIN__ is defined. configure script takes
+ * care of this, not defining HAVE_WINDOWS_H, HAVE_WINSOCK_H, HAVE_WINSOCK2_H,
+ * neither HAVE_WS2TCPIP_H when __CYGWIN__ is defined.
+ */
+
+#ifdef HAVE_WINDOWS_H
+# if defined(UNICODE) && !defined(_UNICODE)
+# define _UNICODE
+# endif
+# if defined(_UNICODE) && !defined(UNICODE)
+# define UNICODE
+# endif
+# ifndef WIN32_LEAN_AND_MEAN
+# define WIN32_LEAN_AND_MEAN
+# endif
+# include <windows.h>
+# ifdef HAVE_WINSOCK2_H
+# include <winsock2.h>
+# ifdef HAVE_WS2TCPIP_H
+# include <ws2tcpip.h>
+# endif
+# else
+# ifdef HAVE_WINSOCK_H
+# include <winsock.h>
+# 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
+ * define USE_WINSOCK to 1 if we have and use WINSOCK API, else
+ * undefine USE_WINSOCK.
+ */
+
+#undef USE_WINSOCK
+
+#ifdef HAVE_WINSOCK2_H
+# define USE_WINSOCK 2
+#else
+# ifdef HAVE_WINSOCK_H
+# define USE_WINSOCK 1
+# endif
+#endif
+
+#ifdef USE_LWIPSOCK
+# include <lwip/init.h>
+# include <lwip/sockets.h>
+# include <lwip/netdb.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRICMP_H
+# include <extra/stricmp.h>
+#endif
+
+#ifdef HAVE_EXTRA_STRDUP_H
+# include <extra/strdup.h>
+#endif
+
+#ifdef TPF
+# include <strings.h> /* for bzero, strcasecmp, and strncasecmp */
+# include <string.h> /* for strcpy and strlen */
+# include <stdlib.h> /* for rand and srand */
+# include <sys/socket.h> /* for select and ioctl*/
+# include <netdb.h> /* for in_addr_t definition */
+# include <tpf/sysapi.h> /* for tpf_process_signals */
+ /* change which select is used for libcurl */
+# define select(a,b,c,d,e) tpf_select_libcurl(a,b,c,d,e)
+#endif
+
+#ifdef __VXWORKS__
+# include <sockLib.h> /* for generic BSD socket functions */
+# include <ioLib.h> /* for basic I/O interface functions */
+#endif
+
+#ifdef __AMIGA__
+# ifndef __ixemul__
+# include <exec/types.h>
+# include <exec/execbase.h>
+# include <proto/exec.h>
+# include <proto/dos.h>
+# define select(a,b,c,d,e) WaitSelect(a,b,c,d,e,0)
+# endif
+#endif
+
+#include <stdio.h>
+#ifdef HAVE_ASSERT_H
+#include <assert.h>
+#endif
+
+#ifdef __TANDEM /* for nsr-tandem-nsk systems */
+#include <floss.h>
+#endif
+
+#ifndef STDC_HEADERS /* no standard C headers! */
+#include <curl/stdcheaders.h>
+#endif
+
+#ifdef __POCC__
+# include <sys/types.h>
+# include <unistd.h>
+# define sys_nerr EILSEQ
+#endif
+
+/*
+ * Salford-C kludge section (mostly borrowed from wxWidgets).
+ */
+#ifdef __SALFORDC__
+ #pragma suppress 353 /* Possible nested comments */
+ #pragma suppress 593 /* Define not used */
+ #pragma suppress 61 /* enum has no name */
+ #pragma suppress 106 /* unnamed, unused parameter */
+ #include <clib.h>
+#endif
+
+/*
+ * Large file (>2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_LARGE_FILES
+# include <io.h>
+# include <sys/types.h>
+# 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
+#endif
+
+/*
+ * Small file (<2Gb) support using WIN32 functions.
+ */
+
+#ifdef USE_WIN32_SMALL_FILES
+# include <io.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+# ifndef _WIN32_WCE
+# undef lseek
+# define lseek(fdes,offset,whence) _lseek(fdes, (long)offset, whence)
+# define fstat(fdes,stp) _fstat(fdes, stp)
+# define stat(fname,stp) _stat(fname, stp)
+# define struct_stat struct _stat
+# endif
+# define LSEEK_ERROR (long)-1
+#endif
+
+#ifndef struct_stat
+# define struct_stat struct stat
+#endif
+
+#ifndef LSEEK_ERROR
+# define LSEEK_ERROR (off_t)-1
+#endif
+
+/*
+ * Default sizeof(off_t) in case it hasn't been defined in config file.
+ */
+
+#ifndef SIZEOF_OFF_T
+# if defined(__VMS) && !defined(__VAX)
+# if defined(_LARGEFILE)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__OS400__) && defined(__ILEC400__)
+# if defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__MVS__) && defined(__IBMC__)
+# if defined(_LP64) || defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# elif defined(__370__) && defined(__IBMC__)
+# if defined(_LP64) || defined(_LARGE_FILES)
+# define SIZEOF_OFF_T 8
+# endif
+# endif
+# ifndef SIZEOF_OFF_T
+# define SIZEOF_OFF_T 4
+# endif
+#endif
+
+/*
+ * Arg 2 type for gethostname in case it hasn't been defined in config file.
+ */
+
+#ifndef GETHOSTNAME_TYPE_ARG2
+# ifdef USE_WINSOCK
+# define GETHOSTNAME_TYPE_ARG2 int
+# else
+# define GETHOSTNAME_TYPE_ARG2 size_t
+# endif
+#endif
+
+/* Below we define some functions. They should
+
+ 4. set the SIGALRM signal timeout
+ 5. set dir/file naming defines
+ */
+
+#ifdef WIN32
+
+# define DIR_CHAR "\\"
+# define DOT_CHAR "_"
+
+#else /* WIN32 */
+
+# ifdef MSDOS /* Watt-32 */
+
+# include <sys/ioctl.h>
+# define select(n,r,w,x,t) select_s(n,r,w,x,t)
+# define ioctl(x,y,z) ioctlsocket(x,y,(char *)(z))
+# include <tcp.h>
+# ifdef word
+# undef word
+# endif
+# ifdef byte
+# undef byte
+# endif
+
+# endif /* MSDOS */
+
+# ifdef __minix
+ /* Minix 3 versions up to at least 3.1.3 are missing these prototypes */
+ extern char * strtok_r(char *s, const char *delim, char **last);
+ extern struct tm * gmtime_r(const time_t * const timep, struct tm *tmp);
+# endif
+
+# define DIR_CHAR "/"
+# ifndef DOT_CHAR
+# define DOT_CHAR "."
+# endif
+
+# ifdef MSDOS
+# undef DOT_CHAR
+# define DOT_CHAR "_"
+# endif
+
+# ifndef fileno /* sunos 4 have this as a macro! */
+ int fileno( FILE *stream);
+# endif
+
+#endif /* WIN32 */
+
+/*
+ * msvc 6.0 requires PSDK in order to have INET6_ADDRSTRLEN
+ * defined in ws2tcpip.h as well as to provide IPv6 support.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# if !defined(HAVE_WS2TCPIP_H) || \
+ ((_MSC_VER < 1300) && !defined(INET6_ADDRSTRLEN))
+# undef HAVE_GETADDRINFO_THREADSAFE
+# undef HAVE_FREEADDRINFO
+# undef HAVE_GETADDRINFO
+# undef HAVE_GETNAMEINFO
+# undef ENABLE_IPV6
+# endif
+#endif
+
+/* ---------------------------------------------------------------- */
+/* resolver specialty compile-time defines */
+/* CURLRES_* defines to use in the host*.c sources */
+/* ---------------------------------------------------------------- */
+
+/*
+ * lcc-win32 doesn't have _beginthreadex(), lacks threads support.
+ */
+
+#if defined(__LCC__) && defined(WIN32)
+# undef USE_THREADS_POSIX
+# undef USE_THREADS_WIN32
+#endif
+
+/*
+ * MSVC threads support requires a multi-threaded runtime library.
+ * _beginthreadex() is not available in single-threaded ones.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__) && !defined(_MT)
+# undef USE_THREADS_POSIX
+# undef USE_THREADS_WIN32
+#endif
+
+/*
+ * Mutually exclusive CURLRES_* definitions.
+ */
+
+#ifdef USE_ARES
+# define CURLRES_ASYNCH
+# define CURLRES_ARES
+/* now undef the stock libc functions just to avoid them being used */
+# undef HAVE_GETADDRINFO
+# undef HAVE_GETHOSTBYNAME
+#elif defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+# define CURLRES_ASYNCH
+# define CURLRES_THREADED
+#else
+# define CURLRES_SYNCH
+#endif
+
+#ifdef ENABLE_IPV6
+# define CURLRES_IPV6
+#else
+# define CURLRES_IPV4
+#endif
+
+/* ---------------------------------------------------------------- */
+
+/*
+ * When using WINSOCK, TELNET protocol requires WINSOCK2 API.
+ */
+
+#if defined(USE_WINSOCK) && (USE_WINSOCK != 2)
+# define CURL_DISABLE_TELNET 1
+#endif
+
+/*
+ * msvc 6.0 does not have struct sockaddr_storage and
+ * does not define IPPROTO_ESP in winsock2.h. But both
+ * are available if PSDK is properly installed.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# if !defined(HAVE_WINSOCK2_H) || ((_MSC_VER < 1300) && !defined(IPPROTO_ESP))
+# undef HAVE_STRUCT_SOCKADDR_STORAGE
+# endif
+#endif
+
+/*
+ * Intentionally fail to build when using msvc 6.0 without PSDK installed.
+ * The brave of heart can circumvent this, defining ALLOW_MSVC6_WITHOUT_PSDK
+ * in lib/config-win32.h although absolutely discouraged and unsupported.
+ */
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# if !defined(HAVE_WINDOWS_H) || ((_MSC_VER < 1300) && !defined(_FILETIME_))
+# if !defined(ALLOW_MSVC6_WITHOUT_PSDK)
+# error MSVC 6.0 requires "February 2003 Platform SDK" a.k.a. \
+ "Windows Server 2003 PSDK"
+# else
+# define CURL_DISABLE_LDAP 1
+# endif
+# endif
+#endif
+
+#ifdef NETWARE
+int netware_init(void);
+#ifndef __NOVELL_LIBC__
+#include <sys/bsdskt.h>
+#include <sys/timeval.h>
+#endif
+#endif
+
+#if defined(HAVE_LIBIDN) && defined(HAVE_TLD_H)
+/* The lib was present and the tld.h header (which is missing in libidn 0.3.X
+ but we only work with libidn 0.4.1 or later) */
+#define USE_LIBIDN
+#endif
+
+#ifndef SIZEOF_TIME_T
+/* assume default size of time_t to be 32 bit */
+#define SIZEOF_TIME_T 4
+#endif
+
+#define LIBIDN_REQUIRED_VERSION "0.4.1"
+
+#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_GSKIT)
+#define USE_SSL /* SSL support has been enabled */
+#endif
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+#define USE_HTTP_NEGOTIATE
+#endif
+
+/* Single point where USE_NTLM definition might be done */
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_NTLM)
+#if defined(USE_SSLEAY) || defined(USE_WINDOWS_SSPI) || \
+ defined(USE_GNUTLS) || defined(USE_NSS) || defined(USE_DARWINSSL)
+#define USE_NTLM
+#endif
+#endif
+
+/* non-configure builds may define CURL_WANTS_CA_BUNDLE_ENV */
+#if defined(CURL_WANTS_CA_BUNDLE_ENV) && !defined(CURL_CA_BUNDLE)
+#define CURL_CA_BUNDLE getenv("CURL_CA_BUNDLE")
+#endif
+
+/*
+ * Provide a mechanism to silence picky compilers, such as gcc 4.6+.
+ * Parameters should of course normally not be unused, but for example when
+ * we have multiple implementations of the same interface it may happen.
+ */
+
+#if defined(__GNUC__) && ((__GNUC__ >= 3) || \
+ ((__GNUC__ == 2) && defined(__GNUC_MINOR__) && (__GNUC_MINOR__ >= 7)))
+# define UNUSED_PARAM __attribute__((__unused__))
+#else
+# define UNUSED_PARAM /*NOTHING*/
+#endif
+
+/*
+ * Include macros and defines that should only be processed once.
+ */
+
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#include "curl_setup_once.h"
+#endif
+
+/*
+ * Definition of our NOP statement Object-like macro
+ */
+
+#ifndef Curl_nop_stmt
+# define Curl_nop_stmt do { } WHILE_FALSE
+#endif
+
+/*
+ * Ensure that Winsock and lwIP TCP/IP stacks are not mixed.
+ */
+
+#if defined(__LWIP_OPT_H__)
+# if defined(SOCKET) || \
+ defined(USE_WINSOCK) || \
+ defined(HAVE_WINSOCK_H) || \
+ defined(HAVE_WINSOCK2_H) || \
+ defined(HAVE_WS2TCPIP_H)
+# error "Winsock and lwIP TCP/IP stack definitions shall not coexist!"
+# endif
+#endif
+
+/*
+ * Portable symbolic names for Winsock shutdown() mode flags.
+ */
+
+#ifdef USE_WINSOCK
+# define SHUT_RD 0x00
+# define SHUT_WR 0x01
+# define SHUT_RDWR 0x02
+#endif
+
+/* Define S_ISREG if not defined by system headers, f.e. MSVC */
+#if !defined(S_ISREG) && defined(S_IFMT) && defined(S_IFREG)
+#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
+#endif
+
+/* Define S_ISDIR if not defined by system headers, f.e. MSVC */
+#if !defined(S_ISDIR) && defined(S_IFMT) && defined(S_IFDIR)
+#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
+#endif
+
+#endif /* HEADER_CURL_SETUP_H */
diff --git a/libs/libcurl/src/curl_setup_once.h b/libs/libcurl/src/curl_setup_once.h
new file mode 100644
index 0000000000..69d6d47902
--- /dev/null
+++ b/libs/libcurl/src/curl_setup_once.h
@@ -0,0 +1,551 @@
+#ifndef HEADER_CURL_SETUP_ONCE_H
+#define HEADER_CURL_SETUP_ONCE_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.
+ *
+ ***************************************************************************/
+
+
+/*
+ * Inclusion of common header files.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <ctype.h>
+
+#ifdef HAVE_ERRNO_H
+#include <errno.h>
+#endif
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+
+#ifdef NEED_MALLOC_H
+#include <malloc.h>
+#endif
+
+#ifdef NEED_MEMORY_H
+#include <memory.h>
+#endif
+
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+
+#ifdef HAVE_SYS_TIME_H
+#include <sys/time.h>
+#ifdef TIME_WITH_SYS_TIME
+#include <time.h>
+#endif
+#else
+#ifdef HAVE_TIME_H
+#include <time.h>
+#endif
+#endif
+
+#ifdef WIN32
+#include <io.h>
+#include <fcntl.h>
+#endif
+
+#if defined(HAVE_STDBOOL_H) && defined(HAVE_BOOL_T)
+#include <stdbool.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef _APP32_64BIT_OFF_T
+# define OLD_APP32_64BIT_OFF_T _APP32_64BIT_OFF_T
+# undef _APP32_64BIT_OFF_T
+# else
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
+#ifdef HAVE_SYS_SOCKET_H
+#include <sys/socket.h>
+#endif
+
+#ifdef __hpux
+# if !defined(_XOPEN_SOURCE_EXTENDED) || defined(_KERNEL)
+# ifdef OLD_APP32_64BIT_OFF_T
+# define _APP32_64BIT_OFF_T OLD_APP32_64BIT_OFF_T
+# undef OLD_APP32_64BIT_OFF_T
+# endif
+# endif
+#endif
+
+
+/*
+ * Definition of timeval struct for platforms that don't have it.
+ */
+
+#ifndef HAVE_STRUCT_TIMEVAL
+struct timeval {
+ long tv_sec;
+ long tv_usec;
+};
+#endif
+
+
+/*
+ * If we have the MSG_NOSIGNAL define, make sure we use
+ * it as the fourth argument of function send()
+ */
+
+#ifdef HAVE_MSG_NOSIGNAL
+#define SEND_4TH_ARG MSG_NOSIGNAL
+#else
+#define SEND_4TH_ARG 0
+#endif
+
+
+#if defined(__minix)
+/* Minix doesn't support recv on TCP sockets */
+#define sread(x,y,z) (ssize_t)read((RECV_TYPE_ARG1)(x), \
+ (RECV_TYPE_ARG2)(y), \
+ (RECV_TYPE_ARG3)(z))
+
+#elif defined(HAVE_RECV)
+/*
+ * The definitions for the return type and arguments types
+ * of functions recv() and send() belong and come from the
+ * configuration file. Do not define them in any other place.
+ *
+ * HAVE_RECV is defined if you have a function named recv()
+ * which is used to read incoming data from sockets. If your
+ * function has another name then don't define HAVE_RECV.
+ *
+ * If HAVE_RECV is defined then RECV_TYPE_ARG1, RECV_TYPE_ARG2,
+ * RECV_TYPE_ARG3, RECV_TYPE_ARG4 and RECV_TYPE_RETV must also
+ * be defined.
+ *
+ * HAVE_SEND is defined if you have a function named send()
+ * which is used to write outgoing data on a connected socket.
+ * If yours has another name then don't define HAVE_SEND.
+ *
+ * If HAVE_SEND is defined then SEND_TYPE_ARG1, SEND_QUAL_ARG2,
+ * SEND_TYPE_ARG2, SEND_TYPE_ARG3, SEND_TYPE_ARG4 and
+ * SEND_TYPE_RETV must also be defined.
+ */
+
+#if !defined(RECV_TYPE_ARG1) || \
+ !defined(RECV_TYPE_ARG2) || \
+ !defined(RECV_TYPE_ARG3) || \
+ !defined(RECV_TYPE_ARG4) || \
+ !defined(RECV_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_recv
+ /* */
+#else
+#define sread(x,y,z) (ssize_t)recv((RECV_TYPE_ARG1)(x), \
+ (RECV_TYPE_ARG2)(y), \
+ (RECV_TYPE_ARG3)(z), \
+ (RECV_TYPE_ARG4)(0))
+#endif
+#else /* HAVE_RECV */
+#ifndef sread
+ /* */
+ Error Missing_definition_of_macro_sread
+ /* */
+#endif
+#endif /* HAVE_RECV */
+
+
+#if defined(__minix)
+/* Minix doesn't support send on TCP sockets */
+#define swrite(x,y,z) (ssize_t)write((SEND_TYPE_ARG1)(x), \
+ (SEND_TYPE_ARG2)(y), \
+ (SEND_TYPE_ARG3)(z))
+
+#elif defined(HAVE_SEND)
+#if !defined(SEND_TYPE_ARG1) || \
+ !defined(SEND_QUAL_ARG2) || \
+ !defined(SEND_TYPE_ARG2) || \
+ !defined(SEND_TYPE_ARG3) || \
+ !defined(SEND_TYPE_ARG4) || \
+ !defined(SEND_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_send
+ /* */
+#else
+#define swrite(x,y,z) (ssize_t)send((SEND_TYPE_ARG1)(x), \
+ (SEND_TYPE_ARG2)(y), \
+ (SEND_TYPE_ARG3)(z), \
+ (SEND_TYPE_ARG4)(SEND_4TH_ARG))
+#endif
+#else /* HAVE_SEND */
+#ifndef swrite
+ /* */
+ Error Missing_definition_of_macro_swrite
+ /* */
+#endif
+#endif /* HAVE_SEND */
+
+
+#if 0
+#if defined(HAVE_RECVFROM)
+/*
+ * Currently recvfrom is only used on udp sockets.
+ */
+#if !defined(RECVFROM_TYPE_ARG1) || \
+ !defined(RECVFROM_TYPE_ARG2) || \
+ !defined(RECVFROM_TYPE_ARG3) || \
+ !defined(RECVFROM_TYPE_ARG4) || \
+ !defined(RECVFROM_TYPE_ARG5) || \
+ !defined(RECVFROM_TYPE_ARG6) || \
+ !defined(RECVFROM_TYPE_RETV)
+ /* */
+ Error Missing_definition_of_return_and_arguments_types_of_recvfrom
+ /* */
+#else
+#define sreadfrom(s,b,bl,f,fl) (ssize_t)recvfrom((RECVFROM_TYPE_ARG1) (s), \
+ (RECVFROM_TYPE_ARG2 *)(b), \
+ (RECVFROM_TYPE_ARG3) (bl), \
+ (RECVFROM_TYPE_ARG4) (0), \
+ (RECVFROM_TYPE_ARG5 *)(f), \
+ (RECVFROM_TYPE_ARG6 *)(fl))
+#endif
+#else /* HAVE_RECVFROM */
+#ifndef sreadfrom
+ /* */
+ Error Missing_definition_of_macro_sreadfrom
+ /* */
+#endif
+#endif /* HAVE_RECVFROM */
+
+
+#ifdef RECVFROM_TYPE_ARG6_IS_VOID
+# define RECVFROM_ARG6_T int
+#else
+# define RECVFROM_ARG6_T RECVFROM_TYPE_ARG6
+#endif
+#endif /* if 0 */
+
+
+/*
+ * Function-like macro definition used to close a socket.
+ */
+
+#if defined(HAVE_CLOSESOCKET)
+# define sclose(x) closesocket((x))
+#elif defined(HAVE_CLOSESOCKET_CAMEL)
+# define sclose(x) CloseSocket((x))
+#elif defined(HAVE_CLOSE_S)
+# define sclose(x) close_s((x))
+#elif defined(USE_LWIPSOCK)
+# define sclose(x) lwip_close((x))
+#else
+# define sclose(x) close((x))
+#endif
+
+/*
+ * Stack-independent version of fcntl() on sockets:
+ */
+#if defined(USE_LWIPSOCK)
+# define sfcntl lwip_fcntl
+#else
+# define sfcntl fcntl
+#endif
+
+/*
+ * Uppercase macro versions of ANSI/ISO is*() functions/macros which
+ * avoid negative number inputs with argument byte codes > 127.
+ */
+
+#define ISSPACE(x) (isspace((int) ((unsigned char)x)))
+#define ISDIGIT(x) (isdigit((int) ((unsigned char)x)))
+#define ISALNUM(x) (isalnum((int) ((unsigned char)x)))
+#define ISXDIGIT(x) (isxdigit((int) ((unsigned char)x)))
+#define ISGRAPH(x) (isgraph((int) ((unsigned char)x)))
+#define ISALPHA(x) (isalpha((int) ((unsigned char)x)))
+#define ISPRINT(x) (isprint((int) ((unsigned char)x)))
+#define ISUPPER(x) (isupper((int) ((unsigned char)x)))
+#define ISLOWER(x) (islower((int) ((unsigned char)x)))
+#define ISASCII(x) (isascii((int) ((unsigned char)x)))
+
+#define ISBLANK(x) (int)((((unsigned char)x) == ' ') || \
+ (((unsigned char)x) == '\t'))
+
+#define TOLOWER(x) (tolower((int) ((unsigned char)x)))
+
+
+/*
+ * 'bool' stuff compatible with HP-UX headers.
+ */
+
+#if defined(__hpux) && !defined(HAVE_BOOL_T)
+ typedef int bool;
+# define false 0
+# define true 1
+# define HAVE_BOOL_T
+#endif
+
+
+/*
+ * 'bool' exists on platforms with <stdbool.h>, i.e. C99 platforms.
+ * On non-C99 platforms there's no bool, so define an enum for that.
+ * On C99 platforms 'false' and 'true' also exist. Enum uses a
+ * global namespace though, so use bool_false and bool_true.
+ */
+
+#ifndef HAVE_BOOL_T
+ typedef enum {
+ bool_false = 0,
+ bool_true = 1
+ } bool;
+
+/*
+ * Use a define to let 'true' and 'false' use those enums. There
+ * are currently no use of true and false in libcurl proper, but
+ * there are some in the examples. This will cater for any later
+ * code happening to use true and false.
+ */
+# define false bool_false
+# define true bool_true
+# define HAVE_BOOL_T
+#endif
+
+
+/*
+ * Redefine TRUE and FALSE too, to catch current use. With this
+ * change, 'bool found = 1' will give a warning on MIPSPro, but
+ * 'bool found = TRUE' will not. Change tested on IRIX/MIPSPro,
+ * AIX 5.1/Xlc, Tru64 5.1/cc, w/make test too.
+ */
+
+#ifndef TRUE
+#define TRUE true
+#endif
+#ifndef FALSE
+#define FALSE false
+#endif
+
+
+/*
+ * Macro WHILE_FALSE may be used to build single-iteration do-while loops,
+ * avoiding compiler warnings. Mostly intended for other macro definitions.
+ */
+
+#define WHILE_FALSE while(0)
+
+#if defined(_MSC_VER) && !defined(__POCC__)
+# undef WHILE_FALSE
+# if (_MSC_VER < 1500)
+# define WHILE_FALSE while(1, 0)
+# else
+# define WHILE_FALSE \
+__pragma(warning(push)) \
+__pragma(warning(disable:4127)) \
+while(0) \
+__pragma(warning(pop))
+# endif
+#endif
+
+
+/*
+ * Typedef to 'int' if sig_atomic_t is not an available 'typedefed' type.
+ */
+
+#ifndef HAVE_SIG_ATOMIC_T
+typedef int sig_atomic_t;
+#define HAVE_SIG_ATOMIC_T
+#endif
+
+
+/*
+ * Convenience SIG_ATOMIC_T definition
+ */
+
+#ifdef HAVE_SIG_ATOMIC_T_VOLATILE
+#define SIG_ATOMIC_T static sig_atomic_t
+#else
+#define SIG_ATOMIC_T static volatile sig_atomic_t
+#endif
+
+
+/*
+ * Default return type for signal handlers.
+ */
+
+#ifndef RETSIGTYPE
+#define RETSIGTYPE void
+#endif
+
+
+/*
+ * Macro used to include code only in debug builds.
+ */
+
+#ifdef DEBUGBUILD
+#define DEBUGF(x) x
+#else
+#define DEBUGF(x) do { } WHILE_FALSE
+#endif
+
+
+/*
+ * Macro used to include assertion code only in debug builds.
+ */
+
+#if defined(DEBUGBUILD) && defined(HAVE_ASSERT_H)
+#define DEBUGASSERT(x) assert(x)
+#else
+#define DEBUGASSERT(x) do { } WHILE_FALSE
+#endif
+
+
+/*
+ * Macro SOCKERRNO / SET_SOCKERRNO() returns / sets the *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#ifdef USE_WINSOCK
+#define SOCKERRNO ((int)WSAGetLastError())
+#define SET_SOCKERRNO(x) (WSASetLastError((int)(x)))
+#else
+#define SOCKERRNO (errno)
+#define SET_SOCKERRNO(x) (errno = (x))
+#endif
+
+
+/*
+ * Macro ERRNO / SET_ERRNO() returns / sets the NOT *socket-related* errno
+ * (or equivalent) on this platform to hide platform details to code using it.
+ */
+
+#if defined(WIN32) && !defined(USE_LWIPSOCK)
+#define ERRNO ((int)GetLastError())
+#define SET_ERRNO(x) (SetLastError((DWORD)(x)))
+#else
+#define ERRNO (errno)
+#define SET_ERRNO(x) (errno = (x))
+#endif
+
+
+/*
+ * Portable error number symbolic names defined to Winsock error codes.
+ */
+
+#ifdef USE_WINSOCK
+#undef EBADF /* override definition in errno.h */
+#define EBADF WSAEBADF
+#undef EINTR /* override definition in errno.h */
+#define EINTR WSAEINTR
+#undef EINVAL /* override definition in errno.h */
+#define EINVAL WSAEINVAL
+#undef EWOULDBLOCK /* override definition in errno.h */
+#define EWOULDBLOCK WSAEWOULDBLOCK
+#undef EINPROGRESS /* override definition in errno.h */
+#define EINPROGRESS WSAEINPROGRESS
+#undef EALREADY /* override definition in errno.h */
+#define EALREADY WSAEALREADY
+#undef ENOTSOCK /* override definition in errno.h */
+#define ENOTSOCK WSAENOTSOCK
+#undef EDESTADDRREQ /* override definition in errno.h */
+#define EDESTADDRREQ WSAEDESTADDRREQ
+#undef EMSGSIZE /* override definition in errno.h */
+#define EMSGSIZE WSAEMSGSIZE
+#undef EPROTOTYPE /* override definition in errno.h */
+#define EPROTOTYPE WSAEPROTOTYPE
+#undef ENOPROTOOPT /* override definition in errno.h */
+#define ENOPROTOOPT WSAENOPROTOOPT
+#undef EPROTONOSUPPORT /* override definition in errno.h */
+#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
+#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
+#undef EOPNOTSUPP /* override definition in errno.h */
+#define EOPNOTSUPP WSAEOPNOTSUPP
+#define EPFNOSUPPORT WSAEPFNOSUPPORT
+#undef EAFNOSUPPORT /* override definition in errno.h */
+#define EAFNOSUPPORT WSAEAFNOSUPPORT
+#undef EADDRINUSE /* override definition in errno.h */
+#define EADDRINUSE WSAEADDRINUSE
+#undef EADDRNOTAVAIL /* override definition in errno.h */
+#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
+#undef ENETDOWN /* override definition in errno.h */
+#define ENETDOWN WSAENETDOWN
+#undef ENETUNREACH /* override definition in errno.h */
+#define ENETUNREACH WSAENETUNREACH
+#undef ENETRESET /* override definition in errno.h */
+#define ENETRESET WSAENETRESET
+#undef ECONNABORTED /* override definition in errno.h */
+#define ECONNABORTED WSAECONNABORTED
+#undef ECONNRESET /* override definition in errno.h */
+#define ECONNRESET WSAECONNRESET
+#undef ENOBUFS /* override definition in errno.h */
+#define ENOBUFS WSAENOBUFS
+#undef EISCONN /* override definition in errno.h */
+#define EISCONN WSAEISCONN
+#undef ENOTCONN /* override definition in errno.h */
+#define ENOTCONN WSAENOTCONN
+#define ESHUTDOWN WSAESHUTDOWN
+#define ETOOMANYREFS WSAETOOMANYREFS
+#undef ETIMEDOUT /* override definition in errno.h */
+#define ETIMEDOUT WSAETIMEDOUT
+#undef ECONNREFUSED /* override definition in errno.h */
+#define ECONNREFUSED WSAECONNREFUSED
+#undef ELOOP /* override definition in errno.h */
+#define ELOOP WSAELOOP
+#ifndef ENAMETOOLONG /* possible previous definition in errno.h */
+#define ENAMETOOLONG WSAENAMETOOLONG
+#endif
+#define EHOSTDOWN WSAEHOSTDOWN
+#undef EHOSTUNREACH /* override definition in errno.h */
+#define EHOSTUNREACH WSAEHOSTUNREACH
+#ifndef ENOTEMPTY /* possible previous definition in errno.h */
+#define ENOTEMPTY WSAENOTEMPTY
+#endif
+#define EPROCLIM WSAEPROCLIM
+#define EUSERS WSAEUSERS
+#define EDQUOT WSAEDQUOT
+#define ESTALE WSAESTALE
+#define EREMOTE WSAEREMOTE
+#endif
+
+/*
+ * Macro argv_item_t hides platform details to code using it.
+ */
+
+#ifdef __VMS
+#define argv_item_t __char_ptr32
+#else
+#define argv_item_t char *
+#endif
+
+
+/*
+ * We use this ZERO_NULL to avoid picky compiler warnings,
+ * when assigning a NULL pointer to a function pointer var.
+ */
+
+#define ZERO_NULL 0
+
+
+#endif /* HEADER_CURL_SETUP_ONCE_H */
+
diff --git a/libs/libcurl/src/curl_sspi.c b/libs/libcurl/src/curl_sspi.c
new file mode 100644
index 0000000000..e747d86b1d
--- /dev/null
+++ b/libs/libcurl/src/curl_sspi.c
@@ -0,0 +1,126 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+#include "curl_sspi.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"
+
+/* We use our own typedef here since some headers might lack these */
+typedef PSecurityFunctionTable (APIENTRY *INITSECURITYINTERFACE_FN)(VOID);
+
+/* See definition of SECURITY_ENTRYPOINT in sspi.h */
+#ifdef UNICODE
+# ifdef _WIN32_WCE
+# define SECURITYENTRYPOINT L"InitSecurityInterfaceW"
+# else
+# define SECURITYENTRYPOINT "InitSecurityInterfaceW"
+# endif
+#else
+# define SECURITYENTRYPOINT "InitSecurityInterfaceA"
+#endif
+
+/* Handle of security.dll or secur32.dll, depending on Windows version */
+HMODULE s_hSecDll = NULL;
+
+/* Pointer to SSPI dispatch table */
+PSecurityFunctionTable s_pSecFn = NULL;
+
+/*
+ * Curl_sspi_global_init()
+ *
+ * This is used to load the Security Service Provider Interface (SSPI)
+ * dynamic link library portably across all Windows versions, without
+ * the need to directly link libcurl, nor the application using it, at
+ * build time.
+ *
+ * Once this function has been executed, Windows SSPI functions can be
+ * called through the Security Service Provider Interface dispatch table.
+ */
+CURLcode Curl_sspi_global_init(void)
+{
+ OSVERSIONINFO osver;
+ INITSECURITYINTERFACE_FN pInitSecurityInterface;
+
+ /* If security interface is not yet initialized try to do this */
+ if(!s_hSecDll) {
+
+ /* Find out Windows version */
+ memset(&osver, 0, sizeof(osver));
+ osver.dwOSVersionInfoSize = sizeof(osver);
+ if(!GetVersionEx(&osver))
+ return CURLE_FAILED_INIT;
+
+ /* Security Service Provider Interface (SSPI) functions are located in
+ * security.dll on WinNT 4.0 and in secur32.dll on Win9x. Win2K and XP
+ * have both these DLLs (security.dll forwards calls to secur32.dll) */
+
+ /* Load SSPI dll into the address space of the calling process */
+ if(osver.dwPlatformId == VER_PLATFORM_WIN32_NT
+ && osver.dwMajorVersion == 4)
+ s_hSecDll = LoadLibrary(TEXT("security.dll"));
+ else
+ s_hSecDll = LoadLibrary(TEXT("secur32.dll"));
+ if(!s_hSecDll)
+ return CURLE_FAILED_INIT;
+
+ /* Get address of the InitSecurityInterfaceA function from the SSPI dll */
+ pInitSecurityInterface = (INITSECURITYINTERFACE_FN)
+ GetProcAddress(s_hSecDll, SECURITYENTRYPOINT);
+ if(!pInitSecurityInterface)
+ return CURLE_FAILED_INIT;
+
+ /* Get pointer to Security Service Provider Interface dispatch table */
+ s_pSecFn = pInitSecurityInterface();
+ if(!s_pSecFn)
+ return CURLE_FAILED_INIT;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_sspi_global_cleanup()
+ *
+ * This deinitializes the Security Service Provider Interface from libcurl.
+ */
+
+void Curl_sspi_global_cleanup(void)
+{
+ if(s_hSecDll) {
+ FreeLibrary(s_hSecDll);
+ s_hSecDll = NULL;
+ s_pSecFn = NULL;
+ }
+}
+
+#endif /* USE_WINDOWS_SSPI */
diff --git a/libs/libcurl/src/curl_sspi.h b/libs/libcurl/src/curl_sspi.h
new file mode 100644
index 0000000000..d525828564
--- /dev/null
+++ b/libs/libcurl/src/curl_sspi.h
@@ -0,0 +1,293 @@
+#ifndef HEADER_CURL_SSPI_H
+#define HEADER_CURL_SSPI_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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_WINDOWS_SSPI
+
+#include <curl/curl.h>
+
+/*
+ * When including the following three headers, it is mandatory to define either
+ * SECURITY_WIN32 or SECURITY_KERNEL, indicating who is compiling the code.
+ */
+
+#undef SECURITY_WIN32
+#undef SECURITY_KERNEL
+#define SECURITY_WIN32 1
+#include <security.h>
+#include <sspi.h>
+#include <rpc.h>
+
+CURLcode Curl_sspi_global_init(void);
+void Curl_sspi_global_cleanup(void);
+
+/* Forward-declaration of global variables defined in curl_sspi.c */
+
+extern HMODULE s_hSecDll;
+extern PSecurityFunctionTable s_pSecFn;
+
+/* Provide some definitions missing in old headers */
+
+#ifndef SEC_E_INSUFFICIENT_MEMORY
+# define SEC_E_INSUFFICIENT_MEMORY ((HRESULT)0x80090300L)
+#endif
+#ifndef SEC_E_INVALID_HANDLE
+# define SEC_E_INVALID_HANDLE ((HRESULT)0x80090301L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_FUNCTION
+# define SEC_E_UNSUPPORTED_FUNCTION ((HRESULT)0x80090302L)
+#endif
+#ifndef SEC_E_TARGET_UNKNOWN
+# define SEC_E_TARGET_UNKNOWN ((HRESULT)0x80090303L)
+#endif
+#ifndef SEC_E_INTERNAL_ERROR
+# define SEC_E_INTERNAL_ERROR ((HRESULT)0x80090304L)
+#endif
+#ifndef SEC_E_SECPKG_NOT_FOUND
+# define SEC_E_SECPKG_NOT_FOUND ((HRESULT)0x80090305L)
+#endif
+#ifndef SEC_E_NOT_OWNER
+# define SEC_E_NOT_OWNER ((HRESULT)0x80090306L)
+#endif
+#ifndef SEC_E_CANNOT_INSTALL
+# define SEC_E_CANNOT_INSTALL ((HRESULT)0x80090307L)
+#endif
+#ifndef SEC_E_INVALID_TOKEN
+# define SEC_E_INVALID_TOKEN ((HRESULT)0x80090308L)
+#endif
+#ifndef SEC_E_CANNOT_PACK
+# define SEC_E_CANNOT_PACK ((HRESULT)0x80090309L)
+#endif
+#ifndef SEC_E_QOP_NOT_SUPPORTED
+# define SEC_E_QOP_NOT_SUPPORTED ((HRESULT)0x8009030AL)
+#endif
+#ifndef SEC_E_NO_IMPERSONATION
+# define SEC_E_NO_IMPERSONATION ((HRESULT)0x8009030BL)
+#endif
+#ifndef SEC_E_LOGON_DENIED
+# define SEC_E_LOGON_DENIED ((HRESULT)0x8009030CL)
+#endif
+#ifndef SEC_E_UNKNOWN_CREDENTIALS
+# define SEC_E_UNKNOWN_CREDENTIALS ((HRESULT)0x8009030DL)
+#endif
+#ifndef SEC_E_NO_CREDENTIALS
+# define SEC_E_NO_CREDENTIALS ((HRESULT)0x8009030EL)
+#endif
+#ifndef SEC_E_MESSAGE_ALTERED
+# define SEC_E_MESSAGE_ALTERED ((HRESULT)0x8009030FL)
+#endif
+#ifndef SEC_E_OUT_OF_SEQUENCE
+# define SEC_E_OUT_OF_SEQUENCE ((HRESULT)0x80090310L)
+#endif
+#ifndef SEC_E_NO_AUTHENTICATING_AUTHORITY
+# define SEC_E_NO_AUTHENTICATING_AUTHORITY ((HRESULT)0x80090311L)
+#endif
+#ifndef SEC_E_BAD_PKGID
+# define SEC_E_BAD_PKGID ((HRESULT)0x80090316L)
+#endif
+#ifndef SEC_E_CONTEXT_EXPIRED
+# define SEC_E_CONTEXT_EXPIRED ((HRESULT)0x80090317L)
+#endif
+#ifndef SEC_E_INCOMPLETE_MESSAGE
+# define SEC_E_INCOMPLETE_MESSAGE ((HRESULT)0x80090318L)
+#endif
+#ifndef SEC_E_INCOMPLETE_CREDENTIALS
+# define SEC_E_INCOMPLETE_CREDENTIALS ((HRESULT)0x80090320L)
+#endif
+#ifndef SEC_E_BUFFER_TOO_SMALL
+# define SEC_E_BUFFER_TOO_SMALL ((HRESULT)0x80090321L)
+#endif
+#ifndef SEC_E_WRONG_PRINCIPAL
+# define SEC_E_WRONG_PRINCIPAL ((HRESULT)0x80090322L)
+#endif
+#ifndef SEC_E_TIME_SKEW
+# define SEC_E_TIME_SKEW ((HRESULT)0x80090324L)
+#endif
+#ifndef SEC_E_UNTRUSTED_ROOT
+# define SEC_E_UNTRUSTED_ROOT ((HRESULT)0x80090325L)
+#endif
+#ifndef SEC_E_ILLEGAL_MESSAGE
+# define SEC_E_ILLEGAL_MESSAGE ((HRESULT)0x80090326L)
+#endif
+#ifndef SEC_E_CERT_UNKNOWN
+# define SEC_E_CERT_UNKNOWN ((HRESULT)0x80090327L)
+#endif
+#ifndef SEC_E_CERT_EXPIRED
+# define SEC_E_CERT_EXPIRED ((HRESULT)0x80090328L)
+#endif
+#ifndef SEC_E_ENCRYPT_FAILURE
+# define SEC_E_ENCRYPT_FAILURE ((HRESULT)0x80090329L)
+#endif
+#ifndef SEC_E_DECRYPT_FAILURE
+# define SEC_E_DECRYPT_FAILURE ((HRESULT)0x80090330L)
+#endif
+#ifndef SEC_E_ALGORITHM_MISMATCH
+# define SEC_E_ALGORITHM_MISMATCH ((HRESULT)0x80090331L)
+#endif
+#ifndef SEC_E_SECURITY_QOS_FAILED
+# define SEC_E_SECURITY_QOS_FAILED ((HRESULT)0x80090332L)
+#endif
+#ifndef SEC_E_UNFINISHED_CONTEXT_DELETED
+# define SEC_E_UNFINISHED_CONTEXT_DELETED ((HRESULT)0x80090333L)
+#endif
+#ifndef SEC_E_NO_TGT_REPLY
+# define SEC_E_NO_TGT_REPLY ((HRESULT)0x80090334L)
+#endif
+#ifndef SEC_E_NO_IP_ADDRESSES
+# define SEC_E_NO_IP_ADDRESSES ((HRESULT)0x80090335L)
+#endif
+#ifndef SEC_E_WRONG_CREDENTIAL_HANDLE
+# define SEC_E_WRONG_CREDENTIAL_HANDLE ((HRESULT)0x80090336L)
+#endif
+#ifndef SEC_E_CRYPTO_SYSTEM_INVALID
+# define SEC_E_CRYPTO_SYSTEM_INVALID ((HRESULT)0x80090337L)
+#endif
+#ifndef SEC_E_MAX_REFERRALS_EXCEEDED
+# define SEC_E_MAX_REFERRALS_EXCEEDED ((HRESULT)0x80090338L)
+#endif
+#ifndef SEC_E_MUST_BE_KDC
+# define SEC_E_MUST_BE_KDC ((HRESULT)0x80090339L)
+#endif
+#ifndef SEC_E_STRONG_CRYPTO_NOT_SUPPORTED
+# define SEC_E_STRONG_CRYPTO_NOT_SUPPORTED ((HRESULT)0x8009033AL)
+#endif
+#ifndef SEC_E_TOO_MANY_PRINCIPALS
+# define SEC_E_TOO_MANY_PRINCIPALS ((HRESULT)0x8009033BL)
+#endif
+#ifndef SEC_E_NO_PA_DATA
+# define SEC_E_NO_PA_DATA ((HRESULT)0x8009033CL)
+#endif
+#ifndef SEC_E_PKINIT_NAME_MISMATCH
+# define SEC_E_PKINIT_NAME_MISMATCH ((HRESULT)0x8009033DL)
+#endif
+#ifndef SEC_E_SMARTCARD_LOGON_REQUIRED
+# define SEC_E_SMARTCARD_LOGON_REQUIRED ((HRESULT)0x8009033EL)
+#endif
+#ifndef SEC_E_SHUTDOWN_IN_PROGRESS
+# define SEC_E_SHUTDOWN_IN_PROGRESS ((HRESULT)0x8009033FL)
+#endif
+#ifndef SEC_E_KDC_INVALID_REQUEST
+# define SEC_E_KDC_INVALID_REQUEST ((HRESULT)0x80090340L)
+#endif
+#ifndef SEC_E_KDC_UNABLE_TO_REFER
+# define SEC_E_KDC_UNABLE_TO_REFER ((HRESULT)0x80090341L)
+#endif
+#ifndef SEC_E_KDC_UNKNOWN_ETYPE
+# define SEC_E_KDC_UNKNOWN_ETYPE ((HRESULT)0x80090342L)
+#endif
+#ifndef SEC_E_UNSUPPORTED_PREAUTH
+# define SEC_E_UNSUPPORTED_PREAUTH ((HRESULT)0x80090343L)
+#endif
+#ifndef SEC_E_DELEGATION_REQUIRED
+# define SEC_E_DELEGATION_REQUIRED ((HRESULT)0x80090345L)
+#endif
+#ifndef SEC_E_BAD_BINDINGS
+# define SEC_E_BAD_BINDINGS ((HRESULT)0x80090346L)
+#endif
+#ifndef SEC_E_MULTIPLE_ACCOUNTS
+# define SEC_E_MULTIPLE_ACCOUNTS ((HRESULT)0x80090347L)
+#endif
+#ifndef SEC_E_NO_KERB_KEY
+# define SEC_E_NO_KERB_KEY ((HRESULT)0x80090348L)
+#endif
+#ifndef SEC_E_CERT_WRONG_USAGE
+# define SEC_E_CERT_WRONG_USAGE ((HRESULT)0x80090349L)
+#endif
+#ifndef SEC_E_DOWNGRADE_DETECTED
+# define SEC_E_DOWNGRADE_DETECTED ((HRESULT)0x80090350L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_REVOKED
+# define SEC_E_SMARTCARD_CERT_REVOKED ((HRESULT)0x80090351L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED
+# define SEC_E_ISSUING_CA_UNTRUSTED ((HRESULT)0x80090352L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_C
+# define SEC_E_REVOCATION_OFFLINE_C ((HRESULT)0x80090353L)
+#endif
+#ifndef SEC_E_PKINIT_CLIENT_FAILURE
+# define SEC_E_PKINIT_CLIENT_FAILURE ((HRESULT)0x80090354L)
+#endif
+#ifndef SEC_E_SMARTCARD_CERT_EXPIRED
+# define SEC_E_SMARTCARD_CERT_EXPIRED ((HRESULT)0x80090355L)
+#endif
+#ifndef SEC_E_NO_S4U_PROT_SUPPORT
+# define SEC_E_NO_S4U_PROT_SUPPORT ((HRESULT)0x80090356L)
+#endif
+#ifndef SEC_E_CROSSREALM_DELEGATION_FAILURE
+# define SEC_E_CROSSREALM_DELEGATION_FAILURE ((HRESULT)0x80090357L)
+#endif
+#ifndef SEC_E_REVOCATION_OFFLINE_KDC
+# define SEC_E_REVOCATION_OFFLINE_KDC ((HRESULT)0x80090358L)
+#endif
+#ifndef SEC_E_ISSUING_CA_UNTRUSTED_KDC
+# define SEC_E_ISSUING_CA_UNTRUSTED_KDC ((HRESULT)0x80090359L)
+#endif
+#ifndef SEC_E_KDC_CERT_EXPIRED
+# define SEC_E_KDC_CERT_EXPIRED ((HRESULT)0x8009035AL)
+#endif
+#ifndef SEC_E_KDC_CERT_REVOKED
+# define SEC_E_KDC_CERT_REVOKED ((HRESULT)0x8009035BL)
+#endif
+#ifndef SEC_E_INVALID_PARAMETER
+# define SEC_E_INVALID_PARAMETER ((HRESULT)0x8009035DL)
+#endif
+#ifndef SEC_E_DELEGATION_POLICY
+# define SEC_E_DELEGATION_POLICY ((HRESULT)0x8009035EL)
+#endif
+#ifndef SEC_E_POLICY_NLTM_ONLY
+# define SEC_E_POLICY_NLTM_ONLY ((HRESULT)0x8009035FL)
+#endif
+
+#ifndef SEC_I_CONTINUE_NEEDED
+# define SEC_I_CONTINUE_NEEDED ((HRESULT)0x00090312L)
+#endif
+#ifndef SEC_I_COMPLETE_NEEDED
+# define SEC_I_COMPLETE_NEEDED ((HRESULT)0x00090313L)
+#endif
+#ifndef SEC_I_COMPLETE_AND_CONTINUE
+# define SEC_I_COMPLETE_AND_CONTINUE ((HRESULT)0x00090314L)
+#endif
+#ifndef SEC_I_LOCAL_LOGON
+# define SEC_I_LOCAL_LOGON ((HRESULT)0x00090315L)
+#endif
+#ifndef SEC_I_CONTEXT_EXPIRED
+# define SEC_I_CONTEXT_EXPIRED ((HRESULT)0x00090317L)
+#endif
+#ifndef SEC_I_INCOMPLETE_CREDENTIALS
+# define SEC_I_INCOMPLETE_CREDENTIALS ((HRESULT)0x00090320L)
+#endif
+#ifndef SEC_I_RENEGOTIATE
+# define SEC_I_RENEGOTIATE ((HRESULT)0x00090321L)
+#endif
+#ifndef SEC_I_NO_LSA_CONTEXT
+# define SEC_I_NO_LSA_CONTEXT ((HRESULT)0x00090323L)
+#endif
+#ifndef SEC_I_SIGNATURE_NEEDED
+# define SEC_I_SIGNATURE_NEEDED ((HRESULT)0x0009035CL)
+#endif
+
+#endif /* USE_WINDOWS_SSPI */
+#endif /* HEADER_CURL_SSPI_H */
diff --git a/libs/libcurl/src/curl_threads.c b/libs/libcurl/src/curl_threads.c
new file mode 100644
index 0000000000..c9e91f63ab
--- /dev/null
+++ b/libs/libcurl/src/curl_threads.c
@@ -0,0 +1,129 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#include "curl_threads.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"
+
+#if defined(USE_THREADS_POSIX)
+
+struct curl_actual_call {
+ unsigned int (*func)(void *);
+ void *arg;
+};
+
+static void *curl_thread_create_thunk(void *arg)
+{
+ struct curl_actual_call * ac = arg;
+ unsigned int (*func)(void *) = ac->func;
+ void *real_arg = ac->arg;
+
+ free(ac);
+
+ (*func)(real_arg);
+
+ return 0;
+}
+
+curl_thread_t Curl_thread_create(unsigned int (*func) (void*), void *arg)
+{
+ curl_thread_t t;
+ struct curl_actual_call *ac = malloc(sizeof(struct curl_actual_call));
+ if(!ac)
+ return curl_thread_t_null;
+
+ ac->func = func;
+ ac->arg = arg;
+
+ if(pthread_create(&t, NULL, curl_thread_create_thunk, ac) != 0) {
+ free(ac);
+ return curl_thread_t_null;
+ }
+
+ return t;
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+ if(hnd != curl_thread_t_null)
+ pthread_detach(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+ int ret = (pthread_join(*hnd, NULL) == 0);
+
+ *hnd = curl_thread_t_null;
+
+ return ret;
+}
+
+#elif defined(USE_THREADS_WIN32)
+
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*),
+ void *arg)
+{
+#ifdef _WIN32_WCE
+ return CreateThread(NULL, 0, func, arg, 0, NULL);
+#else
+ curl_thread_t t;
+ t = (curl_thread_t)_beginthreadex(NULL, 0, func, arg, 0, NULL);
+ if((t == 0) || (t == (curl_thread_t)-1L))
+ return curl_thread_t_null;
+ return t;
+#endif
+}
+
+void Curl_thread_destroy(curl_thread_t hnd)
+{
+ CloseHandle(hnd);
+}
+
+int Curl_thread_join(curl_thread_t *hnd)
+{
+ int ret = (WaitForSingleObject(*hnd, INFINITE) == WAIT_OBJECT_0);
+
+ Curl_thread_destroy(*hnd);
+
+ *hnd = curl_thread_t_null;
+
+ return ret;
+}
+
+#endif /* USE_THREADS_* */
diff --git a/libs/libcurl/src/curl_threads.h b/libs/libcurl/src/curl_threads.h
new file mode 100644
index 0000000000..d9cec6b294
--- /dev/null
+++ b/libs/libcurl/src/curl_threads.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_THREADS_H
+#define HEADER_CURL_THREADS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#if defined(USE_THREADS_POSIX)
+# define CURL_STDCALL
+# define curl_mutex_t pthread_mutex_t
+# define curl_thread_t pthread_t
+# define curl_thread_t_null (pthread_t)0
+# define Curl_mutex_init(m) pthread_mutex_init(m, NULL)
+# define Curl_mutex_acquire(m) pthread_mutex_lock(m)
+# define Curl_mutex_release(m) pthread_mutex_unlock(m)
+# define Curl_mutex_destroy(m) pthread_mutex_destroy(m)
+#elif defined(USE_THREADS_WIN32)
+# define CURL_STDCALL __stdcall
+# define curl_mutex_t CRITICAL_SECTION
+# define curl_thread_t HANDLE
+# define curl_thread_t_null (HANDLE)0
+# define Curl_mutex_init(m) InitializeCriticalSection(m)
+# define Curl_mutex_acquire(m) EnterCriticalSection(m)
+# define Curl_mutex_release(m) LeaveCriticalSection(m)
+# define Curl_mutex_destroy(m) DeleteCriticalSection(m)
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+curl_thread_t Curl_thread_create(unsigned int (CURL_STDCALL *func) (void*),
+ void *arg);
+
+void Curl_thread_destroy(curl_thread_t hnd);
+
+int Curl_thread_join(curl_thread_t *hnd);
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* HEADER_CURL_THREADS_H */
diff --git a/libs/libcurl/src/curlx.h b/libs/libcurl/src/curlx.h
new file mode 100644
index 0000000000..9dc90a004b
--- /dev/null
+++ b/libs/libcurl/src/curlx.h
@@ -0,0 +1,119 @@
+#ifndef HEADER_CURL_CURLX_H
+#define HEADER_CURL_CURLX_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Defines protos and includes all header files that provide the curlx_*
+ * functions. The curlx_* functions are not part of the libcurl API, but are
+ * stand-alone functions whose sources can be built and linked by apps if need
+ * be.
+ */
+
+#include <curl/mprintf.h>
+/* this is still a public header file that provides the curl_mprintf()
+ functions while they still are offered publicly. They will be made library-
+ private one day */
+
+#include "strequal.h"
+/* "strequal.h" provides the strequal protos */
+
+#include "strtoofft.h"
+/* "strtoofft.h" provides this function: curlx_strtoofft(), returns a
+ curl_off_t number from a given string.
+*/
+
+#include "timeval.h"
+/*
+ "timeval.h" sets up a 'struct timeval' even for platforms that otherwise
+ don't have one and has protos for these functions:
+
+ curlx_tvnow()
+ curlx_tvdiff()
+ curlx_tvdiff_secs()
+*/
+
+#include "nonblock.h"
+/* "nonblock.h" provides curlx_nonblock() */
+
+#include "warnless.h"
+/* "warnless.h" provides functions:
+
+ curlx_ultous()
+ curlx_ultouc()
+ curlx_uztosi()
+*/
+
+/* Now setup curlx_ * names for the functions that are to become curlx_ and
+ be removed from a future libcurl official API:
+ curlx_getenv
+ curlx_mprintf (and its variations)
+ curlx_strequal
+ curlx_strnequal
+
+*/
+
+#define curlx_getenv curl_getenv
+#define curlx_strequal curl_strequal
+#define curlx_strnequal curl_strnequal
+#define curlx_raw_equal Curl_raw_equal
+#define curlx_mvsnprintf curl_mvsnprintf
+#define curlx_msnprintf curl_msnprintf
+#define curlx_maprintf curl_maprintf
+#define curlx_mvaprintf curl_mvaprintf
+#define curlx_msprintf curl_msprintf
+#define curlx_mprintf curl_mprintf
+#define curlx_mfprintf curl_mfprintf
+#define curlx_mvsprintf curl_mvsprintf
+#define curlx_mvprintf curl_mvprintf
+#define curlx_mvfprintf curl_mvfprintf
+
+#ifdef ENABLE_CURLX_PRINTF
+/* If this define is set, we define all "standard" printf() functions to use
+ the curlx_* version instead. It makes the source code transparent and
+ easier to understand/patch. Undefine them first in case _MPRINTF_REPLACE
+ is set. */
+# undef printf
+# undef fprintf
+# undef sprintf
+# undef snprintf
+# undef vprintf
+# undef vfprintf
+# undef vsprintf
+# undef vsnprintf
+# undef aprintf
+# undef vaprintf
+
+# define printf curlx_mprintf
+# define fprintf curlx_mfprintf
+# define sprintf curlx_msprintf
+# define snprintf curlx_msnprintf
+# define vprintf curlx_mvprintf
+# define vfprintf curlx_mvfprintf
+# define vsprintf curlx_mvsprintf
+# define vsnprintf curlx_mvsnprintf
+# define aprintf curlx_maprintf
+# define vaprintf curlx_mvaprintf
+#endif /* ENABLE_CURLX_PRINTF */
+
+#endif /* HEADER_CURL_CURLX_H */
+
diff --git a/libs/libcurl/src/cyassl.c b/libs/libcurl/src/cyassl.c
new file mode 100644
index 0000000000..7c78464d8a
--- /dev/null
+++ b/libs/libcurl/src/cyassl.c
@@ -0,0 +1,611 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all CyaSSL-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_CYASSL
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "cyassl.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.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"
+#include <cyassl/ssl.h>
+#include <cyassl/error.h>
+
+
+static Curl_recv cyassl_recv;
+static Curl_send cyassl_send;
+
+
+static int do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return SSL_FILETYPE_PEM;
+ if(Curl_raw_equal(type, "PEM"))
+ return SSL_FILETYPE_PEM;
+ if(Curl_raw_equal(type, "DER"))
+ return SSL_FILETYPE_ASN1;
+ return -1;
+}
+
+/*
+ * This function loads all the client/CA certificates and CRLs. Setup the TLS
+ * layer and do all necessary magic.
+ */
+static CURLcode
+cyassl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+ SSL_METHOD* req_method = NULL;
+ void* ssl_sessionid = NULL;
+ curl_socket_t sockfd = conn->sock[sockindex];
+
+ if(conssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ /* CyaSSL doesn't support SSLv2 */
+ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "CyaSSL does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+ switch(data->set.ssl.version) {
+ case CURL_SSLVERSION_DEFAULT:
+ /* we try to figure out version */
+ req_method = SSLv23_client_method();
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ req_method = TLSv1_client_method();
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ req_method = SSLv3_client_method();
+ break;
+ default:
+ req_method = TLSv1_client_method();
+ }
+
+ if(!req_method) {
+ failf(data, "SSL: couldn't create a method!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(conssl->ctx)
+ SSL_CTX_free(conssl->ctx);
+ conssl->ctx = SSL_CTX_new(req_method);
+
+ if(!conssl->ctx) {
+ failf(data, "SSL: couldn't create a context!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifndef NO_FILESYSTEM
+ /* load trusted cacert */
+ if(data->set.str[STRING_SSL_CAFILE]) {
+ if(!SSL_CTX_load_verify_locations(conssl->ctx,
+ data->set.str[STRING_SSL_CAFILE],
+ data->set.str[STRING_SSL_CAPATH])) {
+ if(data->set.ssl.verifypeer) {
+ /* Fail if we insiste on successfully verifying the server. */
+ failf(data,"error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s",
+ data->set.str[STRING_SSL_CAFILE]?
+ data->set.str[STRING_SSL_CAFILE]: "none",
+ data->set.str[STRING_SSL_CAPATH]?
+ data->set.str[STRING_SSL_CAPATH] : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate
+ verification is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
+ "none",
+ data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
+ "none");
+ }
+
+ /* Load the client certificate, and private key */
+ if(data->set.str[STRING_CERT] && data->set.str[STRING_KEY]) {
+ int file_type = do_file_type(data->set.str[STRING_CERT_TYPE]);
+
+ if(SSL_CTX_use_certificate_file(conssl->ctx, data->set.str[STRING_CERT],
+ file_type) != 1) {
+ failf(data, "unable to use client certificate (no key or wrong pass"
+ " phrase?)");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ file_type = do_file_type(data->set.str[STRING_KEY_TYPE]);
+ if(SSL_CTX_use_PrivateKey_file(conssl->ctx, data->set.str[STRING_KEY],
+ file_type) != 1) {
+ failf(data, "unable to set private key");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+#else
+ if(CyaSSL_no_filesystem_verify(conssl->ctx)!= SSL_SUCCESS) {
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+#endif /* NO_FILESYSTEM */
+
+ /* 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. */
+ SSL_CTX_set_verify(conssl->ctx,
+ data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
+ NULL);
+
+ /* Let's make an SSL structure */
+ if(conssl->handle)
+ SSL_free(conssl->handle);
+ conssl->handle = SSL_new(conssl->ctx);
+ if(!conssl->handle) {
+ failf(data, "SSL: couldn't create a context (handle)!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+ /* we got a session id, use it! */
+ if(!SSL_set_session(conssl->handle, ssl_sessionid)) {
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ERR_error_string(SSL_get_error(conssl->handle, 0),NULL));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof (data, "SSL re-using session ID\n");
+ }
+
+ /* pass the raw socket into the SSL layer */
+ if(!SSL_set_fd(conssl->handle, (int)sockfd)) {
+ failf(data, "SSL: SSL_set_fd failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ conssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+
+static CURLcode
+cyassl_connect_step2(struct connectdata *conn,
+ int sockindex)
+{
+ int ret = -1;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data* conssl = &conn->ssl[sockindex];
+
+ infof(data, "CyaSSL: Connecting to %s:%d\n",
+ conn->host.name, conn->remote_port);
+
+ conn->recv[sockindex] = cyassl_recv;
+ conn->send[sockindex] = cyassl_send;
+
+ /* Enable RFC2818 checks */
+ if(data->set.ssl.verifyhost) {
+ ret = CyaSSL_check_domain_name(conssl->handle, conn->host.name);
+ if(ret == SSL_FAILURE)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ ret = SSL_connect(conssl->handle);
+ if(ret != 1) {
+ char error_buffer[80];
+ int detail = SSL_get_error(conssl->handle, ret);
+
+ if(SSL_ERROR_WANT_READ == detail) {
+ conssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ else if(SSL_ERROR_WANT_WRITE == detail) {
+ conssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ /* There is no easy way to override only the CN matching.
+ * This will enable the override of both mismatching SubjectAltNames
+ * as also mismatching CN fields */
+ else if(DOMAIN_NAME_MISMATCH == detail) {
+#if 1
+ failf(data, "\tsubject alt name(s) or common name do not match \"%s\"\n",
+ conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+#else
+ /* When the CyaSSL_check_domain_name() is used and you desire to continue
+ * on a DOMAIN_NAME_MISMATCH, i.e. 'data->set.ssl.verifyhost == 0',
+ * CyaSSL version 2.4.0 will fail with an INCOMPLETE_DATA error. The only
+ * way to do this is currently to switch the CyaSSL_check_domain_name()
+ * in and out based on the 'data->set.ssl.verifyhost' value. */
+ if(data->set.ssl.verifyhost) {
+ failf(data,
+ "\tsubject alt name(s) or common name do not match \"%s\"\n",
+ conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ infof(data,
+ "\tsubject alt name(s) and/or common name do not match \"%s\"\n",
+ conn->host.dispname);
+ return CURLE_OK;
+ }
+#endif
+ }
+ else {
+ failf(data, "SSL_connect failed with error %d: %s", detail,
+ ERR_error_string(detail, error_buffer));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+ conssl->connecting_state = ssl_connect_3;
+ infof(data, "SSL connected\n");
+
+ return CURLE_OK;
+}
+
+
+static CURLcode
+cyassl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ void *old_ssl_sessionid=NULL;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ int incache;
+ SSL_SESSION *our_ssl_sessionid;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ our_ssl_sessionid = SSL_get_session(connssl->handle);
+
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+ 0 /* unknown size */);
+ if(retcode) {
+ failf(data, "failed to store ssl session");
+ return retcode;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return retcode;
+}
+
+
+static ssize_t cyassl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ char error_buffer[80];
+ int memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ int rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+
+ if(rc < 0) {
+ int err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_write() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data, "SSL write: %s, errno %d",
+ ERR_error_string(err, error_buffer),
+ SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ }
+ return rc;
+}
+
+void Curl_cyassl_close_all(struct SessionHandle *data)
+{
+ (void)data;
+}
+
+void Curl_cyassl_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *conssl = &conn->ssl[sockindex];
+
+ if(conssl->handle) {
+ (void)SSL_shutdown(conssl->handle);
+ SSL_free (conssl->handle);
+ conssl->handle = NULL;
+ }
+ if(conssl->ctx) {
+ SSL_CTX_free (conssl->ctx);
+ conssl->ctx = NULL;
+ }
+}
+
+static ssize_t cyassl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ char error_buffer[80];
+ int buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ int nread = SSL_read(conn->ssl[num].handle, buf, buffsize);
+
+ if(nread < 0) {
+ int err = SSL_get_error(conn->ssl[num].handle, nread);
+
+ switch(err) {
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_read() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ failf(conn->data, "SSL read: %s, errno %d",
+ ERR_error_string(err, error_buffer),
+ SOCKERRNO);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ return nread;
+}
+
+
+void Curl_cyassl_session_free(void *ptr)
+{
+ (void)ptr;
+ /* CyaSSL reuses sessions on own, no free */
+}
+
+
+size_t Curl_cyassl_version(char *buffer, size_t size)
+{
+#ifdef CYASSL_VERSION
+ return snprintf(buffer, size, "CyaSSL/%s", CYASSL_VERSION);
+#else
+ return snprintf(buffer, size, "CyaSSL/%s", "<1.8.8");
+#endif
+}
+
+
+int Curl_cyassl_init(void)
+{
+ if(CyaSSL_Init() == 0)
+ return 1;
+
+ return -1;
+}
+
+
+bool Curl_cyassl_data_pending(const struct connectdata* conn, int connindex)
+{
+ if(conn->ssl[connindex].handle) /* SSL is in use */
+ return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
+ else
+ return FALSE;
+}
+
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex)
+{
+ int retval = 0;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->handle) {
+ SSL_free (connssl->handle);
+ connssl->handle = NULL;
+ }
+ return retval;
+}
+
+
+static CURLcode
+cyassl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ retcode = cyassl_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ retcode = cyassl_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3==connssl->connecting_state) {
+ retcode = cyassl_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done==connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = cyassl_recv;
+ conn->send[sockindex] = cyassl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+
+CURLcode
+Curl_cyassl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return cyassl_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_cyassl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = cyassl_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+#endif
diff --git a/libs/libcurl/src/cyassl.h b/libs/libcurl/src/cyassl.h
new file mode 100644
index 0000000000..7728a0cf57
--- /dev/null
+++ b/libs/libcurl/src/cyassl.h
@@ -0,0 +1,64 @@
+#ifndef HEADER_CURL_CYASSL_H
+#define HEADER_CURL_CYASSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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_CYASSL
+
+CURLcode Curl_cyassl_connect(struct connectdata *conn, int sockindex);
+bool Curl_cyassl_data_pending(const struct connectdata* conn,int connindex);
+int Curl_cyassl_shutdown(struct connectdata* conn, int sockindex);
+
+/* tell CyaSSL to close down all open information regarding connections (and
+ thus session ID caching etc) */
+void Curl_cyassl_close_all(struct SessionHandle *data);
+
+ /* close a SSL connection */
+void Curl_cyassl_close(struct connectdata *conn, int sockindex);
+
+void Curl_cyassl_session_free(void *ptr);
+size_t Curl_cyassl_version(char *buffer, size_t size);
+int Curl_cyassl_shutdown(struct connectdata *conn, int sockindex);
+int Curl_cyassl_init(void);
+CURLcode Curl_cyassl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* API setup for CyaSSL */
+#define curlssl_init Curl_cyassl_init
+#define curlssl_cleanup() Curl_nop_stmt
+#define curlssl_connect Curl_cyassl_connect
+#define curlssl_connect_nonblocking Curl_cyassl_connect_nonblocking
+#define curlssl_session_free(x) Curl_cyassl_session_free(x)
+#define curlssl_close_all Curl_cyassl_close_all
+#define curlssl_close Curl_cyassl_close
+#define curlssl_shutdown(x,y) Curl_cyassl_shutdown(x,y)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_cyassl_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) Curl_cyassl_data_pending(x,y)
+
+#endif /* USE_CYASSL */
+#endif /* HEADER_CURL_CYASSL_H */
diff --git a/libs/libcurl/src/dict.c b/libs/libcurl/src/dict.c
new file mode 100644
index 0000000000..f5c892197f
--- /dev/null
+++ b/libs/libcurl/src/dict.c
@@ -0,0 +1,284 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#ifndef CURL_DISABLE_DICT
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+
+#include "progress.h"
+#include "strequal.h"
+#include "dict.h"
+#include "rawstr.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"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode dict_do(struct connectdata *conn, bool *done);
+
+/*
+ * DICT protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_dict = {
+ "DICT", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ dict_do, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_DICT, /* defport */
+ CURLPROTO_DICT, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+static char *unescape_word(struct SessionHandle *data, const char *inputbuff)
+{
+ char *newp;
+ char *dictp;
+ char *ptr;
+ int len;
+ char byte;
+ int olen=0;
+
+ newp = curl_easy_unescape(data, inputbuff, 0, &len);
+ if(!newp)
+ return NULL;
+
+ dictp = malloc(((size_t)len)*2 + 1); /* add one for terminating zero */
+ if(dictp) {
+ /* According to RFC2229 section 2.2, these letters need to be escaped with
+ \[letter] */
+ for(ptr = newp;
+ (byte = *ptr) != 0;
+ ptr++) {
+ if((byte <= 32) || (byte == 127) ||
+ (byte == '\'') || (byte == '\"') || (byte == '\\')) {
+ dictp[olen++] = '\\';
+ }
+ dictp[olen++] = byte;
+ }
+ dictp[olen]=0;
+
+ free(newp);
+ }
+ return dictp;
+}
+
+static CURLcode dict_do(struct connectdata *conn, bool *done)
+{
+ char *word;
+ char *eword;
+ char *ppath;
+ char *database = NULL;
+ char *strategy = NULL;
+ char *nthdef = NULL; /* This is not part of the protocol, but required
+ by RFC 2229 */
+ CURLcode result=CURLE_OK;
+ struct SessionHandle *data=conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+ char *path = data->state.path;
+ curl_off_t *bytecount = &data->req.bytecount;
+
+ *done = TRUE; /* unconditionally */
+
+ if(conn->bits.user_passwd) {
+ /* AUTH is missing */
+ }
+
+ if(Curl_raw_nequal(path, DICT_MATCH, sizeof(DICT_MATCH)-1) ||
+ Curl_raw_nequal(path, DICT_MATCH2, sizeof(DICT_MATCH2)-1) ||
+ Curl_raw_nequal(path, DICT_MATCH3, sizeof(DICT_MATCH3)-1)) {
+
+ word = strchr(path, ':');
+ if(word) {
+ word++;
+ database = strchr(word, ':');
+ if(database) {
+ *database++ = (char)0;
+ strategy = strchr(database, ':');
+ if(strategy) {
+ *strategy++ = (char)0;
+ nthdef = strchr(strategy, ':');
+ if(nthdef) {
+ *nthdef = (char)0;
+ }
+ }
+ }
+ }
+
+ if((word == NULL) || (*word == (char)0)) {
+ infof(data, "lookup word is missing\n");
+ word=(char *)"default";
+ }
+ if((database == NULL) || (*database == (char)0)) {
+ database = (char *)"!";
+ }
+ if((strategy == NULL) || (*strategy == (char)0)) {
+ strategy = (char *)".";
+ }
+
+ eword = unescape_word(data, word);
+ if(!eword)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "MATCH "
+ "%s " /* database */
+ "%s " /* strategy */
+ "%s\r\n" /* word */
+ "QUIT\r\n",
+
+ database,
+ strategy,
+ eword
+ );
+
+ free(eword);
+
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ }
+ else if(Curl_raw_nequal(path, DICT_DEFINE, sizeof(DICT_DEFINE)-1) ||
+ Curl_raw_nequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2)-1) ||
+ Curl_raw_nequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3)-1)) {
+
+ word = strchr(path, ':');
+ if(word) {
+ word++;
+ database = strchr(word, ':');
+ if(database) {
+ *database++ = (char)0;
+ nthdef = strchr(database, ':');
+ if(nthdef) {
+ *nthdef = (char)0;
+ }
+ }
+ }
+
+ if((word == NULL) || (*word == (char)0)) {
+ infof(data, "lookup word is missing\n");
+ word=(char *)"default";
+ }
+ if((database == NULL) || (*database == (char)0)) {
+ database = (char *)"!";
+ }
+
+ eword = unescape_word(data, word);
+ if(!eword)
+ return CURLE_OUT_OF_MEMORY;
+
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "DEFINE "
+ "%s " /* database */
+ "%s\r\n" /* word */
+ "QUIT\r\n",
+ database,
+ eword);
+
+ free(eword);
+
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ }
+ else {
+
+ ppath = strchr(path, '/');
+ if(ppath) {
+ int i;
+
+ ppath++;
+ for(i = 0; ppath[i]; i++) {
+ if(ppath[i] == ':')
+ ppath[i] = ' ';
+ }
+ result = Curl_sendf(sockfd, conn,
+ "CLIENT " LIBCURL_NAME " " LIBCURL_VERSION "\r\n"
+ "%s\r\n"
+ "QUIT\r\n", ppath);
+ if(result) {
+ failf(data, "Failed sending DICT request");
+ return result;
+ }
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount, -1, NULL);
+ }
+ }
+
+ return CURLE_OK;
+}
+#endif /*CURL_DISABLE_DICT*/
diff --git a/libs/libcurl/src/dict.h b/libs/libcurl/src/dict.h
new file mode 100644
index 0000000000..44fd9d49d5
--- /dev/null
+++ b/libs/libcurl/src/dict.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_DICT_H
+#define HEADER_CURL_DICT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_DICT
+extern const struct Curl_handler Curl_handler_dict;
+#endif
+
+#endif /* HEADER_CURL_DICT_H */
diff --git a/libs/libcurl/src/dotdot.c b/libs/libcurl/src/dotdot.c
new file mode 100644
index 0000000000..41b73bef41
--- /dev/null
+++ b/libs/libcurl/src/dotdot.c
@@ -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;
+}
diff --git a/libs/libcurl/src/dotdot.h b/libs/libcurl/src/dotdot.h
new file mode 100644
index 0000000000..c3487c137b
--- /dev/null
+++ b/libs/libcurl/src/dotdot.h
@@ -0,0 +1,25 @@
+#ifndef HEADER_CURL_DOTDOT_H
+#define HEADER_CURL_DOTDOT_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.
+ *
+ ***************************************************************************/
+char *Curl_dedotdotify(char *input);
+#endif
diff --git a/libs/libcurl/src/easy.c b/libs/libcurl/src/easy.c
new file mode 100644
index 0000000000..1e718abcba
--- /dev/null
+++ b/libs/libcurl/src/easy.c
@@ -0,0 +1,1223 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+/*
+ * See comment in curl_memory.h for the explanation of this sanity check.
+ */
+
+#ifdef CURLX_NO_MEMORY_CALLBACKS
+#error "libcurl shall not ever be built with CURLX_NO_MEMORY_CALLBACKS defined"
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#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>
+#include "transfer.h"
+#include "sslgen.h"
+#include "url.h"
+#include "getinfo.h"
+#include "hostip.h"
+#include "share.h"
+#include "strdup.h"
+#include "curl_memory.h"
+#include "progress.h"
+#include "easyif.h"
+#include "select.h"
+#include "sendf.h" /* for failf function prototype */
+#include "curl_ntlm.h"
+#include "connect.h" /* for Curl_getconnectinfo */
+#include "slist.h"
+#include "amigaos.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>
+
+/* 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)
+{
+#ifdef USE_WINSOCK
+ WSACleanup();
+#endif
+#ifdef USE_WINDOWS_SSPI
+ Curl_sspi_global_cleanup();
+#endif
+}
+
+/* win32_init() performs win32 socket initialization to properly setup the
+ stack to allow networking */
+static CURLcode win32_init(void)
+{
+#ifdef USE_WINSOCK
+ WORD wVersionRequested;
+ WSADATA wsaData;
+ int res;
+
+#if defined(ENABLE_IPV6) && (USE_WINSOCK < 2)
+ Error IPV6_requires_winsock2
+#endif
+
+ wVersionRequested = MAKEWORD(USE_WINSOCK, USE_WINSOCK);
+
+ res = WSAStartup(wVersionRequested, &wsaData);
+
+ if(res != 0)
+ /* Tell the user that we couldn't find a useable */
+ /* winsock.dll. */
+ return CURLE_FAILED_INIT;
+
+ /* Confirm that the Windows Sockets DLL supports what we need.*/
+ /* Note that if the DLL supports versions greater */
+ /* than wVersionRequested, it will still return */
+ /* wVersionRequested in wVersion. wHighVersion contains the */
+ /* highest supported version. */
+
+ if(LOBYTE( wsaData.wVersion ) != LOBYTE(wVersionRequested) ||
+ HIBYTE( wsaData.wVersion ) != HIBYTE(wVersionRequested) ) {
+ /* Tell the user that we couldn't find a useable */
+
+ /* winsock.dll. */
+ WSACleanup();
+ return CURLE_FAILED_INIT;
+ }
+ /* The Windows Sockets DLL is acceptable. Proceed. */
+#elif defined(USE_LWIPSOCK)
+ lwip_init();
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+ {
+ CURLcode err = Curl_sspi_global_init();
+ if(err != CURLE_OK)
+ return err;
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+#ifdef USE_LIBIDN
+/*
+ * Initialise use of IDNA library.
+ * It falls back to ASCII if $CHARSET isn't defined. This doesn't work for
+ * idna_to_ascii_lz().
+ */
+static void idna_init (void)
+{
+#ifdef WIN32
+ char buf[60];
+ UINT cp = GetACP();
+
+ if(!getenv("CHARSET") && cp > 0) {
+ snprintf(buf, sizeof(buf), "CHARSET=cp%u", cp);
+ putenv(buf);
+ }
+#else
+ /* to do? */
+#endif
+}
+#endif /* USE_LIBIDN */
+
+/* true globals -- for curl_global_init() and curl_global_cleanup() */
+static unsigned int initialized;
+static long init_flags;
+
+/*
+ * strdup (and other memory functions) is redefined in complicated
+ * ways, but at this point it must be defined as the system-supplied strdup
+ * so the callback pointer is initialized correctly.
+ */
+#if defined(_WIN32_WCE)
+#define system_strdup _strdup
+#elif !defined(HAVE_STRDUP)
+#define system_strdup curlx_strdup
+#else
+#define system_strdup strdup
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+# pragma warning(disable:4232) /* MSVC extension, dllimport identity */
+#endif
+
+#ifndef __SYMBIAN32__
+/*
+ * If a memory-using function (like curl_getenv) is used before
+ * curl_global_init() is called, we need to have these pointers set already.
+ */
+curl_malloc_callback Curl_cmalloc = (curl_malloc_callback)malloc;
+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;
+#if defined(WIN32) && defined(UNICODE)
+curl_wcsdup_callback Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+#endif
+#else
+/*
+ * Symbian OS doesn't support initialization to code in writeable static data.
+ * Initialization will occur in the curl_global_init() call.
+ */
+curl_malloc_callback Curl_cmalloc;
+curl_free_callback Curl_cfree;
+curl_realloc_callback Curl_crealloc;
+curl_strdup_callback Curl_cstrdup;
+curl_calloc_callback Curl_ccalloc;
+#endif
+
+#if defined(_MSC_VER) && defined(_DLL) && !defined(__POCC__)
+# pragma warning(default:4232) /* MSVC extension, dllimport identity */
+#endif
+
+/**
+ * curl_global_init() globally initializes cURL given a bitwise set of the
+ * different features of what to initialize.
+ */
+CURLcode curl_global_init(long flags)
+{
+ if(initialized++)
+ return CURLE_OK;
+
+ /* Setup the default memory functions here (again) */
+ Curl_cmalloc = (curl_malloc_callback)malloc;
+ Curl_cfree = (curl_free_callback)free;
+ Curl_crealloc = (curl_realloc_callback)realloc;
+ Curl_cstrdup = (curl_strdup_callback)system_strdup;
+ Curl_ccalloc = (curl_calloc_callback)calloc;
+#if defined(WIN32) && defined(UNICODE)
+ Curl_cwcsdup = (curl_wcsdup_callback)_wcsdup;
+#endif
+
+ if(flags & CURL_GLOBAL_SSL)
+ if(!Curl_ssl_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_ssl_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+ if(flags & CURL_GLOBAL_WIN32)
+ if(win32_init() != CURLE_OK) {
+ DEBUGF(fprintf(stderr, "Error: win32_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+#ifdef __AMIGA__
+ if(!Curl_amiga_init()) {
+ DEBUGF(fprintf(stderr, "Error: Curl_amiga_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+#endif
+
+#ifdef NETWARE
+ if(netware_init()) {
+ DEBUGF(fprintf(stderr, "Warning: LONG namespace not available\n"));
+ }
+#endif
+
+#ifdef USE_LIBIDN
+ idna_init();
+#endif
+
+ if(Curl_resolver_global_init() != CURLE_OK) {
+ DEBUGF(fprintf(stderr, "Error: resolver_global_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+
+#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_INIT)
+ if(libssh2_init(0)) {
+ DEBUGF(fprintf(stderr, "Error: libssh2_init failed\n"));
+ return CURLE_FAILED_INIT;
+ }
+#endif
+
+ if(flags & CURL_GLOBAL_ACK_EINTR)
+ Curl_ack_eintr = 1;
+
+ init_flags = flags;
+
+ return CURLE_OK;
+}
+
+/*
+ * curl_global_init_mem() globally initializes cURL and also registers the
+ * user provided callback routines.
+ */
+CURLcode curl_global_init_mem(long flags, curl_malloc_callback m,
+ curl_free_callback f, curl_realloc_callback r,
+ curl_strdup_callback s, curl_calloc_callback c)
+{
+ CURLcode code = CURLE_OK;
+
+ /* Invalid input, return immediately */
+ if(!m || !f || !r || !s || !c)
+ return CURLE_FAILED_INIT;
+
+ /* Already initialized, don't do it again */
+ if(initialized)
+ return CURLE_OK;
+
+ /* Call the actual init function first */
+ code = curl_global_init(flags);
+ if(code == CURLE_OK) {
+ Curl_cmalloc = m;
+ Curl_cfree = f;
+ Curl_cstrdup = s;
+ Curl_crealloc = r;
+ Curl_ccalloc = c;
+ }
+
+ return code;
+}
+
+/**
+ * curl_global_cleanup() globally cleanups cURL, uses the value of
+ * "init_flags" to determine what needs to be cleaned up and what doesn't.
+ */
+void curl_global_cleanup(void)
+{
+ if(!initialized)
+ return;
+
+ if(--initialized)
+ return;
+
+ Curl_global_host_cache_dtor();
+
+ if(init_flags & CURL_GLOBAL_SSL)
+ Curl_ssl_cleanup();
+
+ Curl_resolver_global_cleanup();
+
+ if(init_flags & CURL_GLOBAL_WIN32)
+ win32_cleanup();
+
+ Curl_amiga_cleanup();
+
+#if defined(USE_LIBSSH2) && defined(HAVE_LIBSSH2_EXIT)
+ (void)libssh2_exit();
+#endif
+
+ init_flags = 0;
+}
+
+/*
+ * curl_easy_init() is the external interface to alloc, setup and init an
+ * easy handle that is returned. If anything goes wrong, NULL is returned.
+ */
+CURL *curl_easy_init(void)
+{
+ CURLcode res;
+ struct SessionHandle *data;
+
+ /* Make sure we inited the global SSL stuff */
+ if(!initialized) {
+ res = curl_global_init(CURL_GLOBAL_DEFAULT);
+ if(res) {
+ /* something in the global init failed, return nothing */
+ DEBUGF(fprintf(stderr, "Error: curl_global_init failed\n"));
+ return NULL;
+ }
+ }
+
+ /* We use curl_open() with undefined URL so far */
+ res = Curl_open(&data);
+ if(res != CURLE_OK) {
+ DEBUGF(fprintf(stderr, "Error: Curl_open failed\n"));
+ return NULL;
+ }
+
+ return data;
+}
+
+/*
+ * curl_easy_setopt() is the external interface for setting options on an
+ * easy handle.
+ */
+
+#undef curl_easy_setopt
+CURLcode curl_easy_setopt(CURL *curl, CURLoption tag, ...)
+{
+ va_list arg;
+ struct SessionHandle *data = curl;
+ CURLcode ret;
+
+ if(!curl)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ va_start(arg, tag);
+
+ ret = Curl_setopt(data, tag, arg);
+
+ va_end(arg);
+ 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;
+}
+
+
+/*
+ * 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,
+ * runs curl_multi_perform() until the transfer is done, then detaches the
+ * easy handle, destroys the multi handle and returns the easy handle's return
+ * code.
+ *
+ * REALITY: it can't just create and destroy the multi handle that easily. It
+ * 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().
+ */
+static CURLcode easy_perform(struct SessionHandle *data, bool events)
+{
+ CURLM *multi;
+ CURLMcode mcode;
+ CURLcode code = CURLE_OK;
+ SIGPIPE_VARIABLE(pipe_st);
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(data->multi) {
+ failf(data, "easy handled already used in multi handle");
+ return CURLE_FAILED_INIT;
+ }
+
+ if(data->multi_easy)
+ multi = data->multi_easy;
+ else {
+ /* 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;
+ }
+
+ /* Copy the MAXCONNECTS option to the multi handle */
+ curl_multi_setopt(multi, CURLMOPT_MAXCONNECTS, data->set.maxconnects);
+
+ mcode = curl_multi_add_handle(multi, data);
+ if(mcode) {
+ curl_multi_cleanup(multi);
+ if(mcode == CURLM_OUT_OF_MEMORY)
+ return CURLE_OUT_OF_MEMORY;
+ else
+ 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;
+
+ /* 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, 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.
+ */
+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);
+ sigpipe_restore(&pipe_st);
+}
+
+/*
+ * curl_easy_getinfo() is an external interface that allows an app to retrieve
+ * information from a performed transfer and similar.
+ */
+#undef curl_easy_getinfo
+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 *);
+
+ ret = Curl_getinfo(data, info, paramp);
+
+ va_end(arg);
+ return ret;
+}
+
+/*
+ * curl_easy_duphandle() is an external interface to allow duplication of a
+ * given input easy handle. The returned handle will be a new working handle
+ * with all options set exactly as the input source handle.
+ */
+CURL *curl_easy_duphandle(CURL *incurl)
+{
+ struct SessionHandle *data=(struct SessionHandle *)incurl;
+
+ struct SessionHandle *outcurl = calloc(1, sizeof(struct SessionHandle));
+ if(NULL == outcurl)
+ goto fail;
+
+ /*
+ * We setup a few buffers we need. We should probably make them
+ * get setup on-demand in the code, as that would probably decrease
+ * the likeliness of us forgetting to init a buffer here in the future.
+ */
+ outcurl->state.headerbuff = malloc(HEADERSIZE);
+ if(!outcurl->state.headerbuff)
+ goto fail;
+ outcurl->state.headersize = HEADERSIZE;
+
+ /* copy all userdefined values */
+ if(Curl_dupset(outcurl, data) != CURLE_OK)
+ goto fail;
+
+ /* the connection cache is setup on demand */
+ outcurl->state.conn_cache = NULL;
+
+ outcurl->state.lastconnect = NULL;
+
+ outcurl->progress.flags = data->progress.flags;
+ outcurl->progress.callback = data->progress.callback;
+
+ if(data->cookies) {
+ /* If cookies are enabled in the parent handle, we enable them
+ in the clone as well! */
+ outcurl->cookies = Curl_cookie_init(data,
+ data->cookies->filename,
+ outcurl->cookies,
+ data->set.cookiesession);
+ if(!outcurl->cookies)
+ goto fail;
+ }
+
+ /* duplicate all values in 'change' */
+ if(data->change.cookielist) {
+ outcurl->change.cookielist =
+ Curl_slist_duplicate(data->change.cookielist);
+ if(!outcurl->change.cookielist)
+ goto fail;
+ }
+
+ if(data->change.url) {
+ outcurl->change.url = strdup(data->change.url);
+ if(!outcurl->change.url)
+ goto fail;
+ outcurl->change.url_alloc = TRUE;
+ }
+
+ if(data->change.referer) {
+ outcurl->change.referer = strdup(data->change.referer);
+ if(!outcurl->change.referer)
+ goto fail;
+ outcurl->change.referer_alloc = TRUE;
+ }
+
+ /* Clone the resolver handle, if present, for the new handle */
+ if(Curl_resolver_duphandle(&outcurl->state.resolver,
+ data->state.resolver) != CURLE_OK)
+ goto fail;
+
+ Curl_convert_setup(outcurl);
+
+ outcurl->magic = CURLEASY_MAGIC_NUMBER;
+
+ /* we reach this point and thus we are OK */
+
+ return outcurl;
+
+ fail:
+
+ if(outcurl) {
+ curl_slist_free_all(outcurl->change.cookielist);
+ outcurl->change.cookielist = NULL;
+ Curl_safefree(outcurl->state.headerbuff);
+ Curl_safefree(outcurl->change.url);
+ Curl_safefree(outcurl->change.referer);
+ Curl_freeset(outcurl);
+ free(outcurl);
+ }
+
+ return NULL;
+}
+
+/*
+ * curl_easy_reset() is an external interface that allows an app to re-
+ * initialize a session handle to the default values.
+ */
+void curl_easy_reset(CURL *curl)
+{
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+
+ Curl_safefree(data->state.pathbuffer);
+
+ data->state.path = NULL;
+
+ Curl_free_request_state(data);
+
+ /* zero out UserDefined data: */
+ Curl_freeset(data);
+ memset(&data->set, 0, sizeof(struct UserDefined));
+ (void)Curl_init_userdefined(&data->set);
+
+ /* zero out Progress data: */
+ memset(&data->progress, 0, sizeof(struct Progress));
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+}
+
+/*
+ * curl_easy_pause() allows an application to pause or unpause a specific
+ * transfer and direction. This function sets the full new state for the
+ * current connection this easy handle operates on.
+ *
+ * NOTE: if you have the receiving paused and you call this function to remove
+ * the pausing, you may get your write callback called at this point.
+ *
+ * Action is a bitmask consisting of CURLPAUSE_* bits in curl/curl.h
+ */
+CURLcode curl_easy_pause(CURL *curl, int action)
+{
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+ struct SingleRequest *k = &data->req;
+ CURLcode result = CURLE_OK;
+
+ /* first switch off both pause bits */
+ int newstate = k->keepon &~ (KEEP_RECV_PAUSE| KEEP_SEND_PAUSE);
+
+ /* set the new desired pause bits */
+ newstate |= ((action & CURLPAUSE_RECV)?KEEP_RECV_PAUSE:0) |
+ ((action & CURLPAUSE_SEND)?KEEP_SEND_PAUSE:0);
+
+ /* put it back in the keepon */
+ k->keepon = newstate;
+
+ if(!(newstate & KEEP_RECV_PAUSE) && data->state.tempwrite) {
+ /* we have a buffer for sending that we now seem to be able to deliver
+ since the receive pausing is lifted! */
+
+ /* get the pointer, type and length in local copies since the function may
+ return PAUSE again and then we'll get a new copy allocted and stored in
+ the tempwrite variables */
+ char *tempwrite = data->state.tempwrite;
+ char *freewrite = tempwrite; /* store this pointer to free it later */
+ size_t tempsize = data->state.tempwritesize;
+ int temptype = data->state.tempwritetype;
+ size_t chunklen;
+
+ /* clear tempwrite here just to make sure it gets cleared if there's no
+ further use of it, and make sure we don't clear it after the function
+ invoke as it may have been set to a new value by then */
+ data->state.tempwrite = NULL;
+
+ /* since the write callback API is define to never exceed
+ CURL_MAX_WRITE_SIZE bytes in a single call, and since we may in fact
+ have more data than that in our buffer here, we must loop sending the
+ data in multiple calls until there's no data left or we get another
+ pause returned.
+
+ A tricky part is that the function we call will "buffer" the data
+ itself when it pauses on a particular buffer, so we may need to do some
+ extra trickery if we get a pause return here.
+ */
+ do {
+ chunklen = (tempsize > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:tempsize;
+
+ result = Curl_client_write(data->easy_conn,
+ temptype, tempwrite, chunklen);
+ if(result)
+ /* failures abort the loop at once */
+ break;
+
+ if(data->state.tempwrite && (tempsize - chunklen)) {
+ /* Ouch, the reading is again paused and the block we send is now
+ "cached". If this is the final chunk we can leave it like this, but
+ if we have more chunks that are cached after this, we need to free
+ the newly cached one and put back a version that is truly the entire
+ contents that is saved for later
+ */
+ char *newptr;
+
+ /* note that tempsize is still the size as before the callback was
+ used, and thus the whole piece of data to keep */
+ newptr = realloc(data->state.tempwrite, tempsize);
+
+ if(!newptr) {
+ free(data->state.tempwrite); /* free old area */
+ data->state.tempwrite = NULL;
+ result = CURLE_OUT_OF_MEMORY;
+ /* tempwrite will be freed further down */
+ break;
+ }
+ data->state.tempwrite = newptr; /* store new pointer */
+ memcpy(newptr, tempwrite, tempsize);
+ data->state.tempwritesize = tempsize; /* store new size */
+ /* tempwrite will be freed further down */
+ break; /* go back to pausing until further notice */
+ }
+ else {
+ tempsize -= chunklen; /* left after the call above */
+ tempwrite += chunklen; /* advance the pointer */
+ }
+
+ } while((result == CURLE_OK) && tempsize);
+
+ 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;
+}
+
+
+static CURLcode easy_connection(struct SessionHandle *data,
+ curl_socket_t *sfd,
+ struct connectdata **connp)
+{
+ if(data == NULL)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ /* only allow these to be called on handles with CURLOPT_CONNECT_ONLY */
+ if(!data->set.connect_only) {
+ failf(data, "CONNECT_ONLY is required!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+
+ *sfd = Curl_getconnectinfo(data, connp);
+
+ if(*sfd == CURL_SOCKET_BAD) {
+ failf(data, "Failed to get recent socket");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Receives data from the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ * Returns CURLE_OK on success, error code on error.
+ */
+CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, size_t *n)
+{
+ curl_socket_t sfd;
+ CURLcode ret;
+ ssize_t n1;
+ struct connectdata *c;
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+
+ ret = easy_connection(data, &sfd, &c);
+ if(ret)
+ return ret;
+
+ *n = 0;
+ ret = Curl_read(c, sfd, buffer, buflen, &n1);
+
+ if(ret != CURLE_OK)
+ return ret;
+
+ *n = (size_t)n1;
+
+ return CURLE_OK;
+}
+
+/*
+ * Sends data over the connected socket. Use after successful
+ * curl_easy_perform() with CURLOPT_CONNECT_ONLY option.
+ */
+CURLcode curl_easy_send(CURL *curl, const void *buffer, size_t buflen,
+ size_t *n)
+{
+ curl_socket_t sfd;
+ CURLcode ret;
+ ssize_t n1;
+ struct connectdata *c = NULL;
+ struct SessionHandle *data = (struct SessionHandle *)curl;
+
+ ret = easy_connection(data, &sfd, &c);
+ if(ret)
+ return ret;
+
+ *n = 0;
+ ret = Curl_write(c, sfd, buffer, buflen, &n1);
+
+ if(n1 == -1)
+ return CURLE_SEND_ERROR;
+
+ /* detect EAGAIN */
+ if((CURLE_OK == ret) && (0 == n1))
+ return CURLE_AGAIN;
+
+ *n = (size_t)n1;
+
+ return ret;
+}
diff --git a/libs/libcurl/src/easyif.h b/libs/libcurl/src/easyif.h
new file mode 100644
index 0000000000..043ff437d4
--- /dev/null
+++ b/libs/libcurl/src/easyif.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_EASYIF_H
+#define HEADER_CURL_EASYIF_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.
+ *
+ ***************************************************************************/
+
+/*
+ * Prototypes for library-wide functions provided by easy.c
+ */
+#ifdef CURLDEBUG
+CURL_EXTERN CURLcode curl_easy_perform_ev(CURL *easy);
+#endif
+
+#endif /* HEADER_CURL_EASYIF_H */
+
diff --git a/libs/libcurl/src/escape.c b/libs/libcurl/src/escape.c
new file mode 100644
index 0000000000..aa7db2c5b9
--- /dev/null
+++ b/libs/libcurl/src/escape.c
@@ -0,0 +1,234 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred. */
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "curl_memory.h"
+#include "urldata.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "escape.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Portable character check (remember EBCDIC). Do not use isalnum() because
+ its behavior is altered by the current locale.
+ See http://tools.ietf.org/html/rfc3986#section-2.3
+*/
+static bool Curl_isunreserved(unsigned char in)
+{
+ switch (in) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'a': case 'b': case 'c': case 'd': case 'e':
+ case 'f': case 'g': case 'h': case 'i': case 'j':
+ case 'k': case 'l': case 'm': case 'n': case 'o':
+ case 'p': case 'q': case 'r': case 's': case 't':
+ case 'u': case 'v': case 'w': case 'x': case 'y': case 'z':
+ case 'A': case 'B': case 'C': case 'D': case 'E':
+ case 'F': case 'G': case 'H': case 'I': case 'J':
+ case 'K': case 'L': case 'M': case 'N': case 'O':
+ case 'P': case 'Q': case 'R': case 'S': case 'T':
+ case 'U': case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case '-': case '.': case '_': case '~':
+ return TRUE;
+ default:
+ break;
+ }
+ return FALSE;
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_escape(const char *string, int inlength)
+{
+ return curl_easy_escape(NULL, string, inlength);
+}
+
+/* for ABI-compatibility with previous versions */
+char *curl_unescape(const char *string, int length)
+{
+ return curl_easy_unescape(NULL, string, length, NULL);
+}
+
+char *curl_easy_escape(CURL *handle, const char *string, int inlength)
+{
+ size_t alloc = (inlength?(size_t)inlength:strlen(string))+1;
+ char *ns;
+ char *testing_ptr = NULL;
+ unsigned char in; /* we need to treat the characters unsigned */
+ size_t newlen = alloc;
+ size_t strindex=0;
+ size_t length;
+ CURLcode res;
+
+ ns = malloc(alloc);
+ if(!ns)
+ return NULL;
+
+ length = alloc-1;
+ while(length--) {
+ in = *string;
+
+ if(Curl_isunreserved(in))
+ /* just copy this */
+ ns[strindex++]=in;
+ else {
+ /* encode it */
+ newlen += 2; /* the size grows with two, since this'll become a %XX */
+ if(newlen > alloc) {
+ alloc *= 2;
+ testing_ptr = realloc(ns, alloc);
+ if(!testing_ptr) {
+ free( ns );
+ return NULL;
+ }
+ else {
+ ns = testing_ptr;
+ }
+ }
+
+ res = Curl_convert_to_network(handle, &in, 1);
+ if(res) {
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ free(ns);
+ return NULL;
+ }
+
+ snprintf(&ns[strindex], 4, "%%%02X", in);
+
+ strindex+=3;
+ }
+ string++;
+ }
+ ns[strindex]=0; /* terminate it */
+ return ns;
+}
+
+/*
+ * Curl_urldecode() URL decodes the given string.
+ *
+ * Optionally detects control characters (byte codes lower than 32) in the
+ * data and rejects such data.
+ *
+ * Returns a pointer to a malloced string in *ostring with length given in
+ * *olen. If length == 0, the length is assumed to be strlen(string).
+ *
+ */
+CURLcode Curl_urldecode(struct SessionHandle *data,
+ const char *string, size_t length,
+ char **ostring, size_t *olen,
+ bool reject_ctrl)
+{
+ size_t alloc = (length?length:strlen(string))+1;
+ char *ns = malloc(alloc);
+ unsigned char in;
+ size_t strindex=0;
+ unsigned long hex;
+ CURLcode res;
+
+ if(!ns)
+ return CURLE_OUT_OF_MEMORY;
+
+ while(--alloc > 0) {
+ in = *string;
+ if(('%' == in) && (alloc > 2) &&
+ ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
+ /* this is two hexadecimal digits following a '%' */
+ char hexstr[3];
+ char *ptr;
+ hexstr[0] = string[1];
+ hexstr[1] = string[2];
+ hexstr[2] = 0;
+
+ hex = strtoul(hexstr, &ptr, 16);
+
+ in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
+
+ res = Curl_convert_from_network(data, &in, 1);
+ if(res) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(ns);
+ return res;
+ }
+
+ string+=2;
+ alloc-=2;
+ }
+ if(reject_ctrl && (in < 0x20)) {
+ free(ns);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ ns[strindex++] = in;
+ string++;
+ }
+ ns[strindex]=0; /* terminate it */
+
+ if(olen)
+ /* store output size */
+ *olen = strindex;
+
+ if(ostring)
+ /* store output string */
+ *ostring = ns;
+
+ return CURLE_OK;
+}
+
+/*
+ * Unescapes the given URL escaped string of given length. Returns a
+ * pointer to a malloced string with length given in *olen.
+ * If length == 0, the length is assumed to be strlen(string).
+ * If olen == NULL, no output length is stored.
+ */
+char *curl_easy_unescape(CURL *handle, const char *string, int length,
+ int *olen)
+{
+ char *str = NULL;
+ size_t inputlen = length;
+ size_t outputlen;
+ CURLcode res = Curl_urldecode(handle, string, inputlen, &str, &outputlen,
+ FALSE);
+ if(res)
+ return NULL;
+ if(olen)
+ *olen = curlx_uztosi(outputlen);
+ return str;
+}
+
+/* For operating systems/environments that use different malloc/free
+ systems for the app and for this library, we provide a free that uses
+ the library's memory system */
+void curl_free(void *p)
+{
+ if(p)
+ free(p);
+}
diff --git a/libs/libcurl/src/escape.h b/libs/libcurl/src/escape.h
new file mode 100644
index 0000000000..731b13655f
--- /dev/null
+++ b/libs/libcurl/src/escape.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_ESCAPE_H
+#define HEADER_CURL_ESCAPE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+/* Escape and unescape URL encoding in strings. The functions return a new
+ * allocated string or NULL if an error occurred. */
+
+CURLcode Curl_urldecode(struct SessionHandle *data,
+ const char *string, size_t length,
+ char **ostring, size_t *olen,
+ bool reject_crlf);
+
+#endif /* HEADER_CURL_ESCAPE_H */
+
diff --git a/libs/libcurl/src/file.c b/libs/libcurl/src/file.c
new file mode 100644
index 0000000000..e658ada0aa
--- /dev/null
+++ b/libs/libcurl/src/file.c
@@ -0,0 +1,582 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_FILE
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "strtoofft.h"
+#include "urldata.h"
+#include <curl/curl.h>
+#include "progress.h"
+#include "sendf.h"
+#include "escape.h"
+#include "file.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+#include "transfer.h"
+#include "url.h"
+#include "curl_memory.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#if defined(WIN32) || defined(MSDOS) || defined(__EMX__) || \
+ defined(__SYMBIAN32__)
+#define DOS_FILESYSTEM 1
+#endif
+
+#ifdef OPEN_NEEDS_ARG3
+# define open_readonly(p,f) open((p),(f),(0))
+#else
+# define open_readonly(p,f) open((p),(f))
+#endif
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode file_do(struct connectdata *, bool *done);
+static CURLcode file_done(struct connectdata *conn,
+ CURLcode status, bool premature);
+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.
+ */
+
+const struct Curl_handler Curl_handler_file = {
+ "FILE", /* scheme */
+ file_setup_connection, /* setup_connection */
+ file_do, /* do_it */
+ file_done, /* done */
+ ZERO_NULL, /* do_more */
+ file_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ file_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ 0, /* defport */
+ CURLPROTO_FILE, /* protocol */
+ PROTOPT_NONETWORK | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+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
+ well be factored out.
+ */
+static CURLcode file_range(struct connectdata *conn)
+{
+ curl_off_t from, to;
+ curl_off_t totalsize=-1;
+ char *ptr;
+ char *ptr2;
+ struct SessionHandle *data = conn->data;
+
+ if(data->state.use_range && data->state.range) {
+ from=curlx_strtoofft(data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if(ptr == ptr2) {
+ /* we didn't get any digit */
+ to=-1;
+ }
+ if((-1 == to) && (from>=0)) {
+ /* X - */
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE %" FORMAT_OFF_T " to end of file\n",
+ from));
+ }
+ else if(from < 0) {
+ /* -Y */
+ data->req.maxdownload = -from;
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE the last %" FORMAT_OFF_T " bytes\n",
+ -from));
+ }
+ else {
+ /* X-Y */
+ totalsize = to-from;
+ data->req.maxdownload = totalsize+1; /* include last byte */
+ data->state.resume_from = from;
+ DEBUGF(infof(data, "RANGE from %" FORMAT_OFF_T
+ " getting %" FORMAT_OFF_T " bytes\n",
+ from, data->req.maxdownload));
+ }
+ DEBUGF(infof(data, "range-download from %" FORMAT_OFF_T
+ " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+ from, to, data->req.maxdownload));
+ }
+ else
+ data->req.maxdownload = -1;
+ return CURLE_OK;
+}
+
+/*
+ * file_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time. We emulate a
+ * connect-then-transfer protocol and "connect" to the file here
+ */
+static CURLcode file_connect(struct connectdata *conn, bool *done)
+{
+ struct SessionHandle *data = conn->data;
+ char *real_path;
+ struct FILEPROTO *file = data->req.protop;
+ int fd;
+#ifdef DOS_FILESYSTEM
+ int i;
+ char *actual_path;
+#endif
+
+ real_path = curl_easy_unescape(data, data->state.path, 0, NULL);
+ if(!real_path)
+ return CURLE_OUT_OF_MEMORY;
+
+#ifdef DOS_FILESYSTEM
+ /* If the first character is a slash, and there's
+ something that looks like a drive at the beginning of
+ the path, skip the slash. If we remove the initial
+ slash in all cases, paths without drive letters end up
+ relative to the current directory which isn't how
+ browsers work.
+
+ Some browsers accept | instead of : as the drive letter
+ separator, so we do too.
+
+ On other platforms, we need the slash to indicate an
+ absolute pathname. On Windows, absolute paths start
+ with a drive letter.
+ */
+ actual_path = real_path;
+ if((actual_path[0] == '/') &&
+ actual_path[1] &&
+ (actual_path[2] == ':' || actual_path[2] == '|')) {
+ actual_path[2] = ':';
+ actual_path++;
+ }
+
+ /* change path separators from '/' to '\\' for DOS, Windows and OS/2 */
+ for(i=0; actual_path[i] != '\0'; ++i)
+ if(actual_path[i] == '/')
+ actual_path[i] = '\\';
+
+ fd = open_readonly(actual_path, O_RDONLY|O_BINARY);
+ file->path = actual_path;
+#else
+ fd = open_readonly(real_path, O_RDONLY);
+ file->path = real_path;
+#endif
+ file->freepath = real_path; /* free this when done */
+
+ file->fd = fd;
+ if(!data->set.upload && (fd == -1)) {
+ failf(data, "Couldn't open file %s", data->state.path);
+ file_done(conn, CURLE_FILE_COULDNT_READ_FILE, FALSE);
+ return CURLE_FILE_COULDNT_READ_FILE;
+ }
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+static CURLcode file_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ (void)status; /* not used */
+ (void)premature; /* not used */
+
+ if(file) {
+ Curl_safefree(file->freepath);
+ file->path = NULL;
+ if(file->fd != -1)
+ close(file->fd);
+ file->fd = -1;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode file_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ (void)dead_connection; /* not used */
+
+ if(file) {
+ Curl_safefree(file->freepath);
+ file->path = NULL;
+ if(file->fd != -1)
+ close(file->fd);
+ file->fd = -1;
+ }
+
+ return CURLE_OK;
+}
+
+#ifdef DOS_FILESYSTEM
+#define DIRSEP '\\'
+#else
+#define DIRSEP '/'
+#endif
+
+static CURLcode file_upload(struct connectdata *conn)
+{
+ struct FILEPROTO *file = conn->data->req.protop;
+ const char *dir = strchr(file->path, DIRSEP);
+ int fd;
+ int mode;
+ CURLcode res=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *buf = data->state.buffer;
+ size_t nread;
+ size_t nwrite;
+ curl_off_t bytecount = 0;
+ struct timeval now = Curl_tvnow();
+ struct_stat file_stat;
+ const char* buf2;
+
+ /*
+ * Since FILE: doesn't do the full init, we need to provide some extra
+ * assignments here.
+ */
+ conn->fread_func = data->set.fread_func;
+ conn->fread_in = data->set.in;
+ conn->data->req.upload_fromhere = buf;
+
+ if(!dir)
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+ if(!dir[1])
+ return CURLE_FILE_COULDNT_READ_FILE; /* fix: better error code */
+
+#ifdef O_BINARY
+#define MODE_DEFAULT O_WRONLY|O_CREAT|O_BINARY
+#else
+#define MODE_DEFAULT O_WRONLY|O_CREAT
+#endif
+
+ if(data->state.resume_from)
+ mode = MODE_DEFAULT|O_APPEND;
+ else
+ mode = MODE_DEFAULT|O_TRUNC;
+
+ fd = open(file->path, mode, conn->data->set.new_file_perms);
+ if(fd < 0) {
+ failf(data, "Can't open %s for writing", file->path);
+ return CURLE_WRITE_ERROR;
+ }
+
+ if(-1 != data->set.infilesize)
+ /* known size of data to "upload" */
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+ /* treat the negative resume offset value as the case of "-" */
+ if(data->state.resume_from < 0) {
+ if(fstat(fd, &file_stat)) {
+ close(fd);
+ failf(data, "Can't get the size of %s", file->path);
+ return CURLE_WRITE_ERROR;
+ }
+ else
+ data->state.resume_from = (curl_off_t)file_stat.st_size;
+ }
+
+ while(res == CURLE_OK) {
+ int readcount;
+ res = Curl_fillreadbuffer(conn, BUFSIZE, &readcount);
+ if(res)
+ break;
+
+ if(readcount <= 0) /* fix questionable compare error. curlvms */
+ break;
+
+ nread = (size_t)readcount;
+
+ /*skip bytes before resume point*/
+ if(data->state.resume_from) {
+ if((curl_off_t)nread <= data->state.resume_from ) {
+ data->state.resume_from -= nread;
+ nread = 0;
+ buf2 = buf;
+ }
+ else {
+ buf2 = buf + data->state.resume_from;
+ nread -= (size_t)data->state.resume_from;
+ data->state.resume_from = 0;
+ }
+ }
+ else
+ buf2 = buf;
+
+ /* write the data to the target */
+ nwrite = write(fd, buf2, nread);
+ if(nwrite != nread) {
+ res = CURLE_SEND_ERROR;
+ break;
+ }
+
+ bytecount += nread;
+
+ Curl_pgrsSetUploadCounter(data, bytecount);
+
+ if(Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+ else
+ res = Curl_speedcheck(data, now);
+ }
+ if(!res && Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+
+ close(fd);
+
+ return res;
+}
+
+/*
+ * file_do() is the protocol-specific function for the do-phase, separated
+ * from the connect-phase above. Other protocols merely setup the transfer in
+ * the do-phase, to have it done in the main transfer loop but since some
+ * platforms we support don't allow select()ing etc on file handles (as
+ * opposed to sockets) we instead perform the whole do-operation in this
+ * function.
+ */
+static CURLcode file_do(struct connectdata *conn, bool *done)
+{
+ /* This implementation ignores the host name in conformance with
+ RFC 1738. Only local files (reachable via the standard file system)
+ are supported. This means that files on remotely mounted directories
+ (via NFS, Samba, NT sharing) can be accessed through a file:// URL
+ */
+ CURLcode res = CURLE_OK;
+ struct_stat statbuf; /* struct_stat instead of struct stat just to allow the
+ Windows version to have a different struct without
+ having to redefine the simple word 'stat' */
+ curl_off_t expected_size=0;
+ bool fstated=FALSE;
+ ssize_t nread;
+ struct SessionHandle *data = conn->data;
+ char *buf = data->state.buffer;
+ curl_off_t bytecount = 0;
+ int fd;
+ struct timeval now = Curl_tvnow();
+ struct FILEPROTO *file;
+
+ *done = TRUE; /* unconditionally */
+
+ Curl_initinfo(data);
+ Curl_pgrsStartNow(data);
+
+ if(data->set.upload)
+ return file_upload(conn);
+
+ file = conn->data->req.protop;
+
+ /* get the fd from the connection phase */
+ fd = file->fd;
+
+ /* VMS: This only works reliable for STREAMLF files */
+ if(-1 != fstat(fd, &statbuf)) {
+ /* we could stat it, then read out the size */
+ expected_size = statbuf.st_size;
+ /* and store the modification time */
+ data->info.filetime = (long)statbuf.st_mtime;
+ fstated = TRUE;
+ }
+
+ if(fstated && !data->state.range && data->set.timecondition) {
+ if(!Curl_meets_timecondition(data, (time_t)data->info.filetime)) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ }
+
+ /* If we have selected NOBODY and HEADER, it means that we only want file
+ information. Which for FILE can't be much more than the file size and
+ date. */
+ if(data->set.opt_no_body && data->set.include_header && fstated) {
+ CURLcode result;
+ snprintf(buf, sizeof(data->state.buffer),
+ "Content-Length: %" FORMAT_OFF_T "\r\n", expected_size);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+ if(result)
+ return result;
+
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH,
+ (char *)"Accept-ranges: bytes\r\n", 0);
+ if(result)
+ return result;
+
+ if(fstated) {
+ time_t filetime = (time_t)statbuf.st_mtime;
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+ result = Curl_gmtime(filetime, &buffer);
+ if(result)
+ return result;
+
+ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+ snprintf(buf, BUFSIZE-1,
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+ }
+ /* if we fstat()ed the file, set the file size to make it available post-
+ transfer */
+ if(fstated)
+ Curl_pgrsSetDownloadSize(data, expected_size);
+ return result;
+ }
+
+ /* Check whether file range has been specified */
+ file_range(conn);
+
+ /* Adjust the start offset in case we want to get the N last bytes
+ * of the stream iff the filesize could be determined */
+ if(data->state.resume_from < 0) {
+ if(!fstated) {
+ failf(data, "Can't get the size of file.");
+ return CURLE_READ_ERROR;
+ }
+ else
+ data->state.resume_from += (curl_off_t)statbuf.st_size;
+ }
+
+ if(data->state.resume_from <= expected_size)
+ expected_size -= data->state.resume_from;
+ else {
+ failf(data, "failed to resume file:// transfer");
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+
+ /* A high water mark has been specified so we obey... */
+ if(data->req.maxdownload > 0)
+ expected_size = data->req.maxdownload;
+
+ if(fstated && (expected_size == 0))
+ return CURLE_OK;
+
+ /* The following is a shortcut implementation of file reading
+ this is both more efficient than the former call to download() and
+ it avoids problems with select() and recv() on file descriptors
+ in Winsock */
+ if(fstated)
+ Curl_pgrsSetDownloadSize(data, expected_size);
+
+ if(data->state.resume_from) {
+ if(data->state.resume_from !=
+ lseek(fd, data->state.resume_from, SEEK_SET))
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+ while(res == CURLE_OK) {
+ /* Don't fill a whole buffer if we want less than all data */
+ size_t bytestoread =
+ (expected_size < CURL_OFF_T_C(BUFSIZE) - CURL_OFF_T_C(1)) ?
+ curlx_sotouz(expected_size) : BUFSIZE - 1;
+
+ nread = read(fd, buf, bytestoread);
+
+ if(nread > 0)
+ buf[nread] = 0;
+
+ if(nread <= 0 || expected_size == 0)
+ break;
+
+ bytecount += nread;
+ expected_size -= nread;
+
+ res = Curl_client_write(conn, CLIENTWRITE_BODY, buf, nread);
+ if(res)
+ return res;
+
+ Curl_pgrsSetDownloadCounter(data, bytecount);
+
+ if(Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+ else
+ res = Curl_speedcheck(data, now);
+ }
+ if(Curl_pgrsUpdate(conn))
+ res = CURLE_ABORTED_BY_CALLBACK;
+
+ return res;
+}
+
+#endif
diff --git a/libs/libcurl/src/file.h b/libs/libcurl/src/file.h
new file mode 100644
index 0000000000..997474bc75
--- /dev/null
+++ b/libs/libcurl/src/file.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_FILE_H
+#define HEADER_CURL_FILE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+
+/****************************************************************************
+ * FILE unique setup
+ ***************************************************************************/
+struct FILEPROTO {
+ char *path; /* the path we operate on */
+ char *freepath; /* pointer to the allocated block we must free, this might
+ differ from the 'path' pointer */
+ int fd; /* open file descriptor to read from! */
+};
+
+#ifndef CURL_DISABLE_FILE
+extern const struct Curl_handler Curl_handler_file;
+#endif
+
+#endif /* HEADER_CURL_FILE_H */
+
diff --git a/libs/libcurl/src/fileinfo.c b/libs/libcurl/src/fileinfo.c
new file mode 100644
index 0000000000..8c8ee981a1
--- /dev/null
+++ b/libs/libcurl/src/fileinfo.c
@@ -0,0 +1,54 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010-2011, 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 "strdup.h"
+#include "fileinfo.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"
+
+struct curl_fileinfo *Curl_fileinfo_alloc(void)
+{
+ struct curl_fileinfo *tmp = malloc(sizeof(struct curl_fileinfo));
+ if(!tmp)
+ return NULL;
+ memset(tmp, 0, sizeof(struct curl_fileinfo));
+ return tmp;
+}
+
+void Curl_fileinfo_dtor(void *user, void *element)
+{
+ struct curl_fileinfo *finfo = element;
+ (void) user;
+ if(!finfo)
+ return;
+
+ Curl_safefree(finfo->b_data);
+
+ free(finfo);
+}
diff --git a/libs/libcurl/src/fileinfo.h b/libs/libcurl/src/fileinfo.h
new file mode 100644
index 0000000000..b0e5e59e12
--- /dev/null
+++ b/libs/libcurl/src/fileinfo.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_FILEINFO_H
+#define HEADER_CURL_FILEINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, 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/curl.h>
+
+struct curl_fileinfo *Curl_fileinfo_alloc(void);
+
+void Curl_fileinfo_dtor(void *, void *);
+
+struct curl_fileinfo *Curl_fileinfo_dup(const struct curl_fileinfo *src);
+
+#endif /* HEADER_CURL_FILEINFO_H */
diff --git a/libs/libcurl/src/formdata.c b/libs/libcurl/src/formdata.c
new file mode 100644
index 0000000000..f718a3e4e9
--- /dev/null
+++ b/libs/libcurl/src/formdata.c
@@ -0,0 +1,1594 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 <curl/curl.h>
+
+#if !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY)
+
+#if defined(HAVE_LIBGEN_H) && defined(HAVE_BASENAME)
+#include <libgen.h>
+#endif
+
+#include "urldata.h" /* for struct SessionHandle */
+#include "formdata.h"
+#include "sslgen.h"
+#include "strequal.h"
+#include "curl_memory.h"
+#include "sendf.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#endif /* !defined(CURL_DISABLE_HTTP) || defined(USE_SSLEAY) */
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifndef HAVE_BASENAME
+static char *Curl_basename(char *path);
+#define basename(x) Curl_basename((x))
+#endif
+
+static size_t readfromfile(struct Form *form, char *buffer, size_t size);
+static char *formboundary(struct SessionHandle *data);
+
+/* What kind of Content-Type to use on un-specified files with unrecognized
+ extensions. */
+#define HTTPPOST_CONTENTTYPE_DEFAULT "application/octet-stream"
+
+#define FORM_FILE_SEPARATOR ','
+#define FORM_TYPE_SEPARATOR ';'
+
+/***************************************************************************
+ *
+ * AddHttpPost()
+ *
+ * Adds a HttpPost structure to the list, if parent_post is given becomes
+ * a subpost of parent_post instead of a direct list element.
+ *
+ * Returns newly allocated HttpPost on success and NULL if malloc failed.
+ *
+ ***************************************************************************/
+static struct curl_httppost *
+AddHttpPost(char *name, size_t namelength,
+ char *value, size_t contentslength,
+ char *buffer, size_t bufferlength,
+ char *contenttype,
+ long flags,
+ struct curl_slist* contentHeader,
+ char *showfilename, char *userp,
+ struct curl_httppost *parent_post,
+ struct curl_httppost **httppost,
+ struct curl_httppost **last_post)
+{
+ struct curl_httppost *post;
+ post = calloc(1, sizeof(struct curl_httppost));
+ if(post) {
+ post->name = name;
+ post->namelength = (long)(name?(namelength?namelength:strlen(name)):0);
+ post->contents = value;
+ post->contentslength = (long)contentslength;
+ post->buffer = buffer;
+ post->bufferlength = (long)bufferlength;
+ post->contenttype = contenttype;
+ post->contentheader = contentHeader;
+ post->showfilename = showfilename;
+ post->userp = userp,
+ post->flags = flags;
+ }
+ else
+ return NULL;
+
+ if(parent_post) {
+ /* now, point our 'more' to the original 'more' */
+ post->more = parent_post->more;
+
+ /* then move the original 'more' to point to ourselves */
+ parent_post->more = post;
+ }
+ else {
+ /* make the previous point to this */
+ if(*last_post)
+ (*last_post)->next = post;
+ else
+ (*httppost) = post;
+
+ (*last_post) = post;
+ }
+ return post;
+}
+
+/***************************************************************************
+ *
+ * AddFormInfo()
+ *
+ * Adds a FormInfo structure to the list presented by parent_form_info.
+ *
+ * Returns newly allocated FormInfo on success and NULL if malloc failed/
+ * parent_form_info is NULL.
+ *
+ ***************************************************************************/
+static FormInfo * AddFormInfo(char *value,
+ char *contenttype,
+ FormInfo *parent_form_info)
+{
+ FormInfo *form_info;
+ form_info = calloc(1, sizeof(struct FormInfo));
+ if(form_info) {
+ if(value)
+ form_info->value = value;
+ if(contenttype)
+ form_info->contenttype = contenttype;
+ form_info->flags = HTTPPOST_FILENAME;
+ }
+ else
+ return NULL;
+
+ if(parent_form_info) {
+ /* now, point our 'more' to the original 'more' */
+ form_info->more = parent_form_info->more;
+
+ /* then move the original 'more' to point to ourselves */
+ parent_form_info->more = form_info;
+ }
+
+ return form_info;
+}
+
+/***************************************************************************
+ *
+ * ContentTypeForFilename()
+ *
+ * Provides content type for filename if one of the known types (else
+ * (either the prevtype or the default is returned).
+ *
+ * Returns some valid contenttype for filename.
+ *
+ ***************************************************************************/
+static const char *ContentTypeForFilename(const char *filename,
+ const char *prevtype)
+{
+ const char *contenttype = NULL;
+ unsigned int i;
+ /*
+ * No type was specified, we scan through a few well-known
+ * extensions and pick the first we match!
+ */
+ struct ContentType {
+ const char *extension;
+ const char *type;
+ };
+ static const struct ContentType ctts[]={
+ {".gif", "image/gif"},
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".txt", "text/plain"},
+ {".html", "text/html"},
+ {".xml", "application/xml"}
+ };
+
+ if(prevtype)
+ /* default to the previously set/used! */
+ contenttype = prevtype;
+ else
+ contenttype = HTTPPOST_CONTENTTYPE_DEFAULT;
+
+ if(filename) { /* in case a NULL was passed in */
+ for(i=0; i<sizeof(ctts)/sizeof(ctts[0]); i++) {
+ if(strlen(filename) >= strlen(ctts[i].extension)) {
+ if(strequal(filename +
+ strlen(filename) - strlen(ctts[i].extension),
+ ctts[i].extension)) {
+ contenttype = ctts[i].type;
+ break;
+ }
+ }
+ }
+ }
+ /* we have a contenttype by now */
+ return contenttype;
+}
+
+/***************************************************************************
+ *
+ * memdup()
+ *
+ * Copies the 'source' data to a newly allocated buffer buffer (that is
+ * returned). Uses buffer_length if not null, else uses strlen to determine
+ * the length of the buffer to be copied
+ *
+ * Returns the new pointer or NULL on failure.
+ *
+ ***************************************************************************/
+static char *memdup(const char *src, size_t buffer_length)
+{
+ size_t length;
+ bool add = FALSE;
+ char *buffer;
+
+ if(buffer_length)
+ length = buffer_length;
+ else if(src) {
+ length = strlen(src);
+ add = TRUE;
+ }
+ else
+ /* no length and a NULL src pointer! */
+ return strdup("");
+
+ buffer = malloc(length+add);
+ if(!buffer)
+ return NULL; /* fail */
+
+ memcpy(buffer, src, length);
+
+ /* if length unknown do null termination */
+ if(add)
+ buffer[length] = '\0';
+
+ return buffer;
+}
+
+/***************************************************************************
+ *
+ * FormAdd()
+ *
+ * Stores a formpost parameter and builds the appropriate linked list.
+ *
+ * Has two principal functionalities: using files and byte arrays as
+ * post parts. Byte arrays are either copied or just the pointer is stored
+ * (as the user requests) while for files only the filename and not the
+ * content is stored.
+ *
+ * While you may have only one byte array for each name, multiple filenames
+ * are allowed (and because of this feature CURLFORM_END is needed after
+ * using CURLFORM_FILE).
+ *
+ * Examples:
+ *
+ * Simple name/value pair with copied contents:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_COPYCONTENTS, "value", CURLFORM_END);
+ *
+ * name/value pair where only the content pointer is remembered:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_PTRCONTENTS, ptr, CURLFORM_CONTENTSLENGTH, 10, CURLFORM_END);
+ * (if CURLFORM_CONTENTSLENGTH is missing strlen () is used)
+ *
+ * storing a filename (CONTENTTYPE is optional!):
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_CONTENTTYPE, "plain/text",
+ * CURLFORM_END);
+ *
+ * storing multiple filenames:
+ * curl_formadd (&post, &last, CURLFORM_COPYNAME, "name",
+ * CURLFORM_FILE, "filename1", CURLFORM_FILE, "filename2", CURLFORM_END);
+ *
+ * Returns:
+ * CURL_FORMADD_OK on success
+ * CURL_FORMADD_MEMORY if the FormInfo allocation fails
+ * CURL_FORMADD_OPTION_TWICE if one option is given twice for one Form
+ * CURL_FORMADD_NULL if a null pointer was given for a char
+ * CURL_FORMADD_MEMORY if the allocation of a FormInfo struct failed
+ * CURL_FORMADD_UNKNOWN_OPTION if an unknown option was used
+ * CURL_FORMADD_INCOMPLETE if the some FormInfo is not complete (or error)
+ * CURL_FORMADD_MEMORY if a HttpPost struct cannot be allocated
+ * CURL_FORMADD_MEMORY if some allocation for string copying failed.
+ * CURL_FORMADD_ILLEGAL_ARRAY if an illegal option is used in an array
+ *
+ ***************************************************************************/
+
+static
+CURLFORMcode FormAdd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ va_list params)
+{
+ FormInfo *first_form, *current_form, *form = NULL;
+ CURLFORMcode return_value = CURL_FORMADD_OK;
+ const char *prevtype = NULL;
+ struct curl_httppost *post = NULL;
+ CURLformoption option;
+ struct curl_forms *forms = NULL;
+ char *array_value=NULL; /* value read from an array */
+
+ /* This is a state variable, that if TRUE means that we're parsing an
+ array that we got passed to us. If FALSE we're parsing the input
+ va_list arguments. */
+ bool array_state = FALSE;
+
+ /*
+ * We need to allocate the first struct to fill in.
+ */
+ first_form = calloc(1, sizeof(struct FormInfo));
+ if(!first_form)
+ return CURL_FORMADD_MEMORY;
+
+ current_form = first_form;
+
+ /*
+ * Loop through all the options set. Break if we have an error to report.
+ */
+ while(return_value == CURL_FORMADD_OK) {
+
+ /* first see if we have more parts of the array param */
+ if(array_state && forms) {
+ /* get the upcoming option from the given array */
+ option = forms->option;
+ array_value = (char *)forms->value;
+
+ forms++; /* advance this to next entry */
+ if(CURLFORM_END == option) {
+ /* end of array state */
+ array_state = FALSE;
+ continue;
+ }
+ }
+ else {
+ /* This is not array-state, get next option */
+ option = va_arg(params, CURLformoption);
+ if(CURLFORM_END == option)
+ break;
+ }
+
+ switch (option) {
+ case CURLFORM_ARRAY:
+ if(array_state)
+ /* we don't support an array from within an array */
+ return_value = CURL_FORMADD_ILLEGAL_ARRAY;
+ else {
+ forms = va_arg(params, struct curl_forms *);
+ if(forms)
+ array_state = TRUE;
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ /*
+ * Set the Name property.
+ */
+ case CURLFORM_PTRNAME:
+#ifdef CURL_DOES_CONVERSIONS
+ /* Treat CURLFORM_PTR like CURLFORM_COPYNAME so that libcurl will copy
+ * the data in all cases so that we'll have safe memory for the eventual
+ * conversion.
+ */
+#else
+ current_form->flags |= HTTPPOST_PTRNAME; /* fall through */
+#endif
+ case CURLFORM_COPYNAME:
+ if(current_form->name)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *name = array_state?
+ array_value:va_arg(params, char *);
+ if(name)
+ current_form->name = name; /* store for the moment */
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ case CURLFORM_NAMELENGTH:
+ if(current_form->namelength)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->namelength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ /*
+ * Set the contents property.
+ */
+ case CURLFORM_PTRCONTENTS:
+ current_form->flags |= HTTPPOST_PTRCONTENTS; /* fall through */
+ case CURLFORM_COPYCONTENTS:
+ if(current_form->value)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *value =
+ array_state?array_value:va_arg(params, char *);
+ if(value)
+ current_form->value = value; /* store for the moment */
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ case CURLFORM_CONTENTSLENGTH:
+ if(current_form->contentslength)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->contentslength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ /* Get contents from a given file name */
+ case CURLFORM_FILECONTENT:
+ if(current_form->flags & (HTTPPOST_PTRCONTENTS|HTTPPOST_READFILE))
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ const char *filename = array_state?
+ array_value:va_arg(params, char *);
+ if(filename) {
+ current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_READFILE;
+ current_form->value_alloc = TRUE;
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ /* We upload a file */
+ case CURLFORM_FILE:
+ {
+ const char *filename = array_state?array_value:
+ va_arg(params, char *);
+
+ if(current_form->value) {
+ if(current_form->flags & HTTPPOST_FILENAME) {
+ if(filename) {
+ char *fname = strdup(filename);
+ if(!fname)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(fname, NULL, current_form);
+ if(!form) {
+ Curl_safefree(fname);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->value_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ else
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ }
+ else {
+ if(filename) {
+ current_form->value = strdup(filename);
+ if(!current_form->value)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ current_form->flags |= HTTPPOST_FILENAME;
+ current_form->value_alloc = TRUE;
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ }
+
+ case CURLFORM_BUFFERPTR:
+ current_form->flags |= HTTPPOST_PTRBUFFER|HTTPPOST_BUFFER;
+ if(current_form->buffer)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *buffer =
+ array_state?array_value:va_arg(params, char *);
+ if(buffer) {
+ current_form->buffer = buffer; /* store for the moment */
+ current_form->value = buffer; /* make it non-NULL to be accepted
+ as fine */
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ case CURLFORM_BUFFERLENGTH:
+ if(current_form->bufferlength)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->bufferlength =
+ array_state?(size_t)array_value:(size_t)va_arg(params, long);
+ break;
+
+ case CURLFORM_STREAM:
+ current_form->flags |= HTTPPOST_CALLBACK;
+ if(current_form->userp)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ char *userp =
+ array_state?array_value:va_arg(params, char *);
+ if(userp) {
+ current_form->userp = userp;
+ current_form->value = userp; /* this isn't strictly true but we
+ derive a value from this later on
+ and we need this non-NULL to be
+ accepted as a fine form part */
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+
+ case CURLFORM_CONTENTTYPE:
+ {
+ const char *contenttype =
+ array_state?array_value:va_arg(params, char *);
+ if(current_form->contenttype) {
+ if(current_form->flags & HTTPPOST_FILENAME) {
+ if(contenttype) {
+ char *type = strdup(contenttype);
+ if(!type)
+ return_value = CURL_FORMADD_MEMORY;
+ else {
+ form = AddFormInfo(NULL, type, current_form);
+ if(!form) {
+ Curl_safefree(type);
+ return_value = CURL_FORMADD_MEMORY;
+ }
+ else {
+ form->contenttype_alloc = TRUE;
+ current_form = form;
+ form = NULL;
+ }
+ }
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ else
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ }
+ else {
+ if(contenttype) {
+ current_form->contenttype = strdup(contenttype);
+ if(!current_form->contenttype)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->contenttype_alloc = TRUE;
+ }
+ else
+ return_value = CURL_FORMADD_NULL;
+ }
+ break;
+ }
+ case CURLFORM_CONTENTHEADER:
+ {
+ /* this "cast increases required alignment of target type" but
+ we consider it OK anyway */
+ struct curl_slist* list = array_state?
+ (struct curl_slist*)array_value:
+ va_arg(params, struct curl_slist*);
+
+ if(current_form->contentheader)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else
+ current_form->contentheader = list;
+
+ break;
+ }
+ case CURLFORM_FILENAME:
+ case CURLFORM_BUFFER:
+ {
+ const char *filename = array_state?array_value:
+ va_arg(params, char *);
+ if(current_form->showfilename)
+ return_value = CURL_FORMADD_OPTION_TWICE;
+ else {
+ current_form->showfilename = strdup(filename);
+ if(!current_form->showfilename)
+ return_value = CURL_FORMADD_MEMORY;
+ else
+ current_form->showfilename_alloc = TRUE;
+ }
+ break;
+ }
+ default:
+ return_value = CURL_FORMADD_UNKNOWN_OPTION;
+ break;
+ }
+ }
+
+ if(CURL_FORMADD_OK != return_value) {
+ /* On error, free allocated fields for all nodes of the FormInfo linked
+ list without deallocating nodes. List nodes are deallocated later on */
+ FormInfo *ptr;
+ for(ptr = first_form; ptr != NULL; ptr = ptr->more) {
+ if(ptr->name_alloc) {
+ Curl_safefree(ptr->name);
+ ptr->name_alloc = FALSE;
+ }
+ if(ptr->value_alloc) {
+ Curl_safefree(ptr->value);
+ ptr->value_alloc = FALSE;
+ }
+ if(ptr->contenttype_alloc) {
+ Curl_safefree(ptr->contenttype);
+ ptr->contenttype_alloc = FALSE;
+ }
+ if(ptr->showfilename_alloc) {
+ Curl_safefree(ptr->showfilename);
+ ptr->showfilename_alloc = FALSE;
+ }
+ }
+ }
+
+ if(CURL_FORMADD_OK == return_value) {
+ /* go through the list, check for completeness and if everything is
+ * alright add the HttpPost item otherwise set return_value accordingly */
+
+ post = NULL;
+ for(form = first_form;
+ form != NULL;
+ form = form->more) {
+ if(((!form->name || !form->value) && !post) ||
+ ( (form->contentslength) &&
+ (form->flags & HTTPPOST_FILENAME) ) ||
+ ( (form->flags & HTTPPOST_FILENAME) &&
+ (form->flags & HTTPPOST_PTRCONTENTS) ) ||
+
+ ( (!form->buffer) &&
+ (form->flags & HTTPPOST_BUFFER) &&
+ (form->flags & HTTPPOST_PTRBUFFER) ) ||
+
+ ( (form->flags & HTTPPOST_READFILE) &&
+ (form->flags & HTTPPOST_PTRCONTENTS) )
+ ) {
+ return_value = CURL_FORMADD_INCOMPLETE;
+ break;
+ }
+ else {
+ 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(f, prevtype));
+ if(!form->contenttype) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->contenttype_alloc = TRUE;
+ }
+ if(!(form->flags & HTTPPOST_PTRNAME) &&
+ (form == first_form) ) {
+ /* Note that there's small risk that form->name is NULL here if the
+ app passed in a bad combo, so we better check for that first. */
+ if(form->name)
+ /* copy name (without strdup; possibly contains null characters) */
+ form->name = memdup(form->name, form->namelength);
+ if(!form->name) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->name_alloc = TRUE;
+ }
+ if(!(form->flags & (HTTPPOST_FILENAME | HTTPPOST_READFILE |
+ HTTPPOST_PTRCONTENTS | HTTPPOST_PTRBUFFER |
+ HTTPPOST_CALLBACK)) ) {
+ /* copy value (without strdup; possibly contains null characters) */
+ form->value = memdup(form->value, form->contentslength);
+ if(!form->value) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+ form->value_alloc = TRUE;
+ }
+ post = AddHttpPost(form->name, form->namelength,
+ form->value, form->contentslength,
+ form->buffer, form->bufferlength,
+ form->contenttype, form->flags,
+ form->contentheader, form->showfilename,
+ form->userp,
+ post, httppost,
+ last_post);
+
+ if(!post) {
+ return_value = CURL_FORMADD_MEMORY;
+ break;
+ }
+
+ if(form->contenttype)
+ prevtype = form->contenttype;
+ }
+ }
+ if(CURL_FORMADD_OK != return_value) {
+ /* On error, free allocated fields for nodes of the FormInfo linked
+ list which are not already owned by the httppost linked list
+ without deallocating nodes. List nodes are deallocated later on */
+ FormInfo *ptr;
+ for(ptr = form; ptr != NULL; ptr = ptr->more) {
+ if(ptr->name_alloc) {
+ Curl_safefree(ptr->name);
+ ptr->name_alloc = FALSE;
+ }
+ if(ptr->value_alloc) {
+ Curl_safefree(ptr->value);
+ ptr->value_alloc = FALSE;
+ }
+ if(ptr->contenttype_alloc) {
+ Curl_safefree(ptr->contenttype);
+ ptr->contenttype_alloc = FALSE;
+ }
+ if(ptr->showfilename_alloc) {
+ Curl_safefree(ptr->showfilename);
+ ptr->showfilename_alloc = FALSE;
+ }
+ }
+ }
+ }
+
+ /* Always deallocate FormInfo linked list nodes without touching node
+ fields given that these have either been deallocated or are owned
+ now by the httppost linked list */
+ while(first_form) {
+ FormInfo *ptr = first_form->more;
+ Curl_safefree(first_form);
+ first_form = ptr;
+ }
+
+ return return_value;
+}
+
+/*
+ * curl_formadd() is a public API to add a section to the multipart formpost.
+ *
+ * @unittest: 1308
+ */
+
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...)
+{
+ va_list arg;
+ CURLFORMcode result;
+ va_start(arg, last_post);
+ result = FormAdd(httppost, last_post, arg);
+ va_end(arg);
+ 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.
+ *
+ * size is incremented by the chunk length, unless it is NULL
+ */
+static CURLcode AddFormData(struct FormData **formp,
+ enum formtype type,
+ const void *line,
+ size_t length,
+ curl_off_t *size)
+{
+ struct FormData *newform = malloc(sizeof(struct FormData));
+ if(!newform)
+ return CURLE_OUT_OF_MEMORY;
+ newform->next = NULL;
+
+ if(type <= FORM_CONTENT) {
+ /* we make it easier for plain strings: */
+ if(!length)
+ length = strlen((char *)line);
+
+ newform->line = malloc(length+1);
+ if(!newform->line) {
+ free(newform);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(newform->line, line, length);
+ newform->length = length;
+ newform->line[length]=0; /* zero terminate for easier debugging */
+ }
+ else
+ /* For callbacks and files we don't have any actual data so we just keep a
+ pointer to whatever this points to */
+ newform->line = (char *)line;
+
+ newform->type = type;
+
+ if(*formp) {
+ (*formp)->next = newform;
+ *formp = newform;
+ }
+ else
+ *formp = newform;
+
+ if(size) {
+ if(type != FORM_FILE)
+ /* for static content as well as callback data we add the size given
+ as input argument */
+ *size += length;
+ else {
+ /* Since this is a file to be uploaded here, add the size of the actual
+ file */
+ if(!strequal("-", newform->line)) {
+ struct_stat file;
+ if(!stat(newform->line, &file) && !S_ISDIR(file.st_mode))
+ *size += filesize(newform->line, file);
+ else
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
+ * AddFormDataf() adds printf()-style formatted data to the formdata chain.
+ */
+
+static CURLcode AddFormDataf(struct FormData **formp,
+ curl_off_t *size,
+ const char *fmt, ...)
+{
+ char s[4096];
+ va_list ap;
+ va_start(ap, fmt);
+ vsnprintf(s, sizeof(s), fmt, ap);
+ va_end(ap);
+
+ return AddFormData(formp, FORM_DATA, s, 0, size);
+}
+
+/*
+ * Curl_formclean() is used from http.c, this cleans a built FormData linked
+ * list
+ */
+void Curl_formclean(struct FormData **form_ptr)
+{
+ struct FormData *next, *form;
+
+ form = *form_ptr;
+ if(!form)
+ return;
+
+ do {
+ next=form->next; /* the following form line */
+ if(form->type <= FORM_CONTENT)
+ free(form->line); /* free the line */
+ free(form); /* free the struct */
+
+ } while((form = next) != NULL); /* continue */
+
+ *form_ptr = NULL;
+}
+
+/*
+ * curl_formget()
+ * Serialize a curl_httppost struct.
+ * Returns 0 on success.
+ *
+ * @unittest: 1308
+ */
+int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append)
+{
+ CURLcode rc;
+ curl_off_t size;
+ struct FormData *data, *ptr;
+
+ rc = Curl_getformdata(NULL, &data, form, NULL, &size);
+ if(rc != CURLE_OK)
+ return (int)rc;
+
+ for(ptr = data; ptr; ptr = ptr->next) {
+ if((ptr->type == FORM_FILE) || (ptr->type == FORM_CALLBACK)) {
+ char buffer[8192];
+ size_t nread;
+ struct Form temp;
+
+ Curl_FormInit(&temp, ptr);
+
+ do {
+ nread = readfromfile(&temp, buffer, sizeof(buffer));
+ if((nread == (size_t) -1) ||
+ (nread > sizeof(buffer)) ||
+ (nread != append(arg, buffer, nread))) {
+ if(temp.fp)
+ fclose(temp.fp);
+ Curl_formclean(&data);
+ return -1;
+ }
+ } while(nread);
+ }
+ else {
+ if(ptr->length != append(arg, ptr->line, ptr->length)) {
+ Curl_formclean(&data);
+ return -1;
+ }
+ }
+ }
+ Curl_formclean(&data);
+ return 0;
+}
+
+/*
+ * curl_formfree() is an external function to free up a whole form post
+ * chain
+ */
+void curl_formfree(struct curl_httppost *form)
+{
+ struct curl_httppost *next;
+
+ if(!form)
+ /* no form to free, just get out of this */
+ return;
+
+ do {
+ next=form->next; /* the following form line */
+
+ /* recurse to sub-contents */
+ if(form->more)
+ curl_formfree(form->more);
+
+ if(!(form->flags & HTTPPOST_PTRNAME) && form->name)
+ free(form->name); /* free the name */
+ if(!(form->flags &
+ (HTTPPOST_PTRCONTENTS|HTTPPOST_BUFFER|HTTPPOST_CALLBACK)) &&
+ form->contents)
+ free(form->contents); /* free the contents */
+ if(form->contenttype)
+ free(form->contenttype); /* free the content type */
+ if(form->showfilename)
+ free(form->showfilename); /* free the faked file name */
+ free(form); /* free the struct */
+
+ } while((form = next) != NULL); /* continue */
+}
+
+#ifndef HAVE_BASENAME
+/*
+ (Quote from The Open Group Base Specifications Issue 6 IEEE Std 1003.1, 2004
+ Edition)
+
+ The basename() function shall take the pathname pointed to by path and
+ return a pointer to the final component of the pathname, deleting any
+ trailing '/' characters.
+
+ If the string pointed to by path consists entirely of the '/' character,
+ basename() shall return a pointer to the string "/". If the string pointed
+ to by path is exactly "//", it is implementation-defined whether '/' or "//"
+ is returned.
+
+ If path is a null pointer or points to an empty string, basename() shall
+ return a pointer to the string ".".
+
+ The basename() function may modify the string pointed to by path, and may
+ return a pointer to static storage that may then be overwritten by a
+ subsequent call to basename().
+
+ The basename() function need not be reentrant. A function that is not
+ required to be reentrant is not required to be thread-safe.
+
+*/
+static char *Curl_basename(char *path)
+{
+ /* Ignore all the details above for now and make a quick and simple
+ implementaion here */
+ char *s1;
+ char *s2;
+
+ s1=strrchr(path, '/');
+ s2=strrchr(path, '\\');
+
+ if(s1 && s2) {
+ path = (s1 > s2? s1 : s2)+1;
+ }
+ else if(s1)
+ path = s1 + 1;
+ else if(s2)
+ path = s2 + 1;
+
+ return path;
+}
+#endif
+
+static char *strippath(const char *fullfile)
+{
+ char *filename;
+ char *base;
+ filename = strdup(fullfile); /* duplicate since basename() may ruin the
+ buffer it works on */
+ if(!filename)
+ return NULL;
+ base = strdup(basename(filename));
+
+ free(filename); /* free temporary buffer */
+
+ return base; /* returns an allocated string or NULL ! */
+}
+
+static CURLcode formdata_add_filename(const struct curl_httppost *file,
+ struct FormData **form,
+ curl_off_t *size)
+{
+ CURLcode result = CURLE_OK;
+ char *filename = file->showfilename;
+ char *filebasename = NULL;
+ char *filename_escaped = NULL;
+
+ if(!filename) {
+ filebasename = strippath(file->contents);
+ if(!filebasename)
+ return CURLE_OUT_OF_MEMORY;
+ filename = filebasename;
+ }
+
+ if(strchr(filename, '\\') || strchr(filename, '"')) {
+ char *p0, *p1;
+
+ /* filename need be escaped */
+ filename_escaped = malloc(strlen(filename)*2+1);
+ if(!filename_escaped)
+ return CURLE_OUT_OF_MEMORY;
+ p0 = filename_escaped;
+ p1 = filename;
+ while(*p1) {
+ if(*p1 == '\\' || *p1 == '"')
+ *p0++ = '\\';
+ *p0++ = *p1++;
+ }
+ *p0 = '\0';
+ filename = filename_escaped;
+ }
+ result = AddFormDataf(form, size,
+ "; filename=\"%s\"",
+ filename);
+ Curl_safefree(filename_escaped);
+ Curl_safefree(filebasename);
+ return result;
+}
+
+/*
+ * Curl_getformdata() converts a linked list of "meta data" into a complete
+ * (possibly huge) multipart formdata. The input list is in 'post', while the
+ * output resulting linked lists gets stored in '*finalform'. *sizep will get
+ * the total size of the whole POST.
+ * A multipart/form_data content-type is built, unless a custom content-type
+ * is passed in 'custom_content_type'.
+ *
+ * This function will not do a failf() for the potential memory failures but
+ * should for all other errors it spots. Just note that this function MAY get
+ * a NULL pointer in the 'data' argument.
+ */
+
+CURLcode Curl_getformdata(struct SessionHandle *data,
+ struct FormData **finalform,
+ struct curl_httppost *post,
+ const char *custom_content_type,
+ curl_off_t *sizep)
+{
+ struct FormData *form = NULL;
+ struct FormData *firstform;
+ struct curl_httppost *file;
+ CURLcode result = CURLE_OK;
+
+ curl_off_t size = 0; /* support potentially ENORMOUS formposts */
+ char *boundary;
+ char *fileboundary = NULL;
+ struct curl_slist* curList;
+
+ *finalform = NULL; /* default form is empty */
+
+ if(!post)
+ return result; /* no input => no output! */
+
+ boundary = formboundary(data);
+ if(!boundary)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Make the first line of the output */
+ result = AddFormDataf(&form, NULL,
+ "%s; boundary=%s\r\n",
+ custom_content_type?custom_content_type:
+ "Content-Type: multipart/form-data",
+ boundary);
+
+ if(result) {
+ Curl_safefree(boundary);
+ return result;
+ }
+ /* we DO NOT include that line in the total size of the POST, since it'll be
+ part of the header! */
+
+ firstform = form;
+
+ do {
+
+ if(size) {
+ result = AddFormDataf(&form, &size, "\r\n");
+ if(result)
+ break;
+ }
+
+ /* boundary */
+ result = AddFormDataf(&form, &size, "--%s\r\n", boundary);
+ if(result)
+ break;
+
+ /* Maybe later this should be disabled when a custom_content_type is
+ passed, since Content-Disposition is not meaningful for all multipart
+ types.
+ */
+ result = AddFormDataf(&form, &size,
+ "Content-Disposition: form-data; name=\"");
+ if(result)
+ break;
+
+ result = AddFormData(&form, FORM_DATA, post->name, post->namelength,
+ &size);
+ if(result)
+ break;
+
+ result = AddFormDataf(&form, &size, "\"");
+ if(result)
+ break;
+
+ if(post->more) {
+ /* If used, this is a link to more file names, we must then do
+ the magic to include several files with the same field name */
+
+ Curl_safefree(fileboundary);
+ fileboundary = formboundary(data);
+ if(!fileboundary) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: multipart/mixed,"
+ " boundary=%s\r\n",
+ fileboundary);
+ if(result)
+ break;
+ }
+
+ file = post;
+
+ do {
+
+ /* If 'showfilename' is set, that is a faked name passed on to us
+ to use to in the formpost. If that is not set, the actually used
+ local file name should be added. */
+
+ if(post->more) {
+ /* if multiple-file */
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s\r\nContent-Disposition: "
+ "attachment",
+ fileboundary);
+ if(result)
+ break;
+ result = formdata_add_filename(file, &form, &size);
+ if(result)
+ break;
+ }
+ else if(post->flags & (HTTPPOST_FILENAME|HTTPPOST_BUFFER|
+ HTTPPOST_CALLBACK)) {
+ /* it should be noted that for the HTTPPOST_FILENAME and
+ HTTPPOST_CALLBACK cases the ->showfilename struct member is always
+ assigned at this point */
+ if(post->showfilename || (post->flags & HTTPPOST_FILENAME)) {
+ result = formdata_add_filename(post, &form, &size);
+ }
+
+ if(result)
+ break;
+ }
+
+ if(file->contenttype) {
+ /* we have a specified type */
+ result = AddFormDataf(&form, &size,
+ "\r\nContent-Type: %s",
+ file->contenttype);
+ if(result)
+ break;
+ }
+
+ curList = file->contentheader;
+ while(curList) {
+ /* Process the additional headers specified for this form */
+ result = AddFormDataf( &form, &size, "\r\n%s", curList->data );
+ if(result)
+ break;
+ curList = curList->next;
+ }
+ if(result)
+ break;
+
+ result = AddFormDataf(&form, &size, "\r\n\r\n");
+ if(result)
+ break;
+
+ if((post->flags & HTTPPOST_FILENAME) ||
+ (post->flags & HTTPPOST_READFILE)) {
+ /* we should include the contents from the specified file */
+ FILE *fileread;
+
+ fileread = strequal("-", file->contents)?
+ stdin:fopen(file->contents, "rb"); /* binary read for win32 */
+
+ /*
+ * VMS: This only allows for stream files on VMS. Stream files are
+ * OK, as are FIXED & VAR files WITHOUT implied CC For implied CC,
+ * every record needs to have a \n appended & 1 added to SIZE
+ */
+
+ if(fileread) {
+ if(fileread != stdin) {
+ /* close the file */
+ fclose(fileread);
+ /* add the file name only - for later reading from this */
+ result = AddFormData(&form, FORM_FILE, file->contents, 0, &size);
+ }
+ else {
+ /* When uploading from stdin, we can't know the size of the file,
+ * thus must read the full file as before. We *could* use chunked
+ * transfer-encoding, but that only works for HTTP 1.1 and we
+ * can't be sure we work with such a server.
+ */
+ size_t nread;
+ char buffer[512];
+ while((nread = fread(buffer, 1, sizeof(buffer), fileread)) != 0) {
+ result = AddFormData(&form, FORM_CONTENT, buffer, nread, &size);
+ if(result)
+ break;
+ }
+ }
+ }
+ else {
+ if(data)
+ failf(data, "couldn't open file \"%s\"", file->contents);
+ *finalform = NULL;
+ result = CURLE_READ_ERROR;
+ }
+ }
+ else if(post->flags & HTTPPOST_BUFFER)
+ /* include contents of buffer */
+ result = AddFormData(&form, FORM_CONTENT, post->buffer,
+ post->bufferlength, &size);
+ else if(post->flags & HTTPPOST_CALLBACK)
+ /* the contents should be read with the callback and the size
+ is set with the contentslength */
+ result = AddFormData(&form, FORM_CALLBACK, post->userp,
+ post->contentslength, &size);
+ else
+ /* include the contents we got */
+ result = AddFormData(&form, FORM_CONTENT, post->contents,
+ post->contentslength, &size);
+
+ file = file->more;
+ } while(file && !result); /* for each specified file for this field */
+
+ if(result)
+ break;
+
+ if(post->more) {
+ /* this was a multiple-file inclusion, make a termination file
+ boundary: */
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s--",
+ fileboundary);
+ if(result)
+ break;
+ }
+
+ } while((post = post->next) != NULL); /* for each field */
+
+ /* end-boundary for everything */
+ if(CURLE_OK == result)
+ result = AddFormDataf(&form, &size,
+ "\r\n--%s--\r\n",
+ boundary);
+
+ if(result) {
+ Curl_formclean(&firstform);
+ Curl_safefree(fileboundary);
+ Curl_safefree(boundary);
+ return result;
+ }
+
+ *sizep = size;
+
+ Curl_safefree(fileboundary);
+ Curl_safefree(boundary);
+
+ *finalform = firstform;
+
+ return result;
+}
+
+/*
+ * Curl_FormInit() inits the struct 'form' points to with the 'formdata'
+ * and resets the 'sent' counter.
+ */
+int Curl_FormInit(struct Form *form, struct FormData *formdata )
+{
+ if(!formdata)
+ return 1; /* error */
+
+ form->data = formdata;
+ form->sent = 0;
+ form->fp = NULL;
+ form->fread_func = ZERO_NULL;
+
+ 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()
+ *
+ * The read callback that this function may use can return a value larger than
+ * 'size' (which then this function returns) that indicates a problem and it
+ * must be properly dealt with
+ */
+static size_t readfromfile(struct Form *form, char *buffer,
+ size_t size)
+{
+ size_t nread;
+ bool callback = (form->data->type == FORM_CALLBACK)?TRUE:FALSE;
+
+ if(callback) {
+ if(form->fread_func == ZERO_NULL)
+ return 0;
+ else
+ nread = form->fread_func(buffer, 1, size, form->data->line);
+ }
+ else {
+ if(!form->fp) {
+ /* this file hasn't yet been opened */
+ form->fp = fopen_read(form->data->line, "rb"); /* b is for binary */
+ if(!form->fp)
+ return (size_t)-1; /* failure */
+ }
+ nread = fread(buffer, 1, size, form->fp);
+ }
+ if(!nread) {
+ /* this is the last chunk from the file, move on */
+ if(form->fp) {
+ fclose(form->fp);
+ form->fp = NULL;
+ }
+ form->data = form->data->next;
+ }
+
+ return nread;
+}
+
+/*
+ * Curl_FormReader() is the fread() emulation function that will be used to
+ * deliver the formdata to the transfer loop and then sent away to the peer.
+ */
+size_t Curl_FormReader(char *buffer,
+ size_t size,
+ size_t nitems,
+ FILE *mydata)
+{
+ struct Form *form;
+ size_t wantedsize;
+ size_t gotsize = 0;
+
+ form=(struct Form *)mydata;
+
+ wantedsize = size * nitems;
+
+ if(!form->data)
+ return 0; /* nothing, error, empty */
+
+ if((form->data->type == FORM_FILE) ||
+ (form->data->type == FORM_CALLBACK)) {
+ gotsize = readfromfile(form, buffer, wantedsize);
+
+ if(gotsize)
+ /* If positive or -1, return. If zero, continue! */
+ return gotsize;
+ }
+ do {
+
+ if((form->data->length - form->sent ) > wantedsize - gotsize) {
+
+ memcpy(buffer + gotsize , form->data->line + form->sent,
+ wantedsize - gotsize);
+
+ form->sent += wantedsize-gotsize;
+
+ return wantedsize;
+ }
+
+ memcpy(buffer+gotsize,
+ form->data->line + form->sent,
+ (form->data->length - form->sent) );
+ gotsize += form->data->length - form->sent;
+
+ form->sent = 0;
+
+ form->data = form->data->next; /* advance */
+
+ } while(form->data && (form->data->type < FORM_CALLBACK));
+ /* If we got an empty line and we have more data, we proceed to the next
+ line immediately to avoid returning zero before we've reached the end. */
+
+ return gotsize;
+}
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len)
+{
+ char *header;
+ struct Form *form=(struct Form *)formp;
+
+ if(!form->data)
+ return 0; /* nothing, ERROR! */
+
+ header = form->data->line;
+ *len = form->data->length;
+
+ form->data = form->data->next; /* advance */
+
+ return header;
+}
+
+/*
+ * formboundary() creates a suitable boundary string and returns an allocated
+ * one.
+ */
+static char *formboundary(struct SessionHandle *data)
+{
+ /* 24 dashes and 16 hexadecimal digits makes 64 bit (18446744073709551615)
+ combinations */
+ return aprintf("------------------------%08x%08x",
+ Curl_rand(data), Curl_rand(data));
+}
+
+#else /* CURL_DISABLE_HTTP */
+CURLFORMcode curl_formadd(struct curl_httppost **httppost,
+ struct curl_httppost **last_post,
+ ...)
+{
+ (void)httppost;
+ (void)last_post;
+ return CURL_FORMADD_DISABLED;
+}
+
+int curl_formget(struct curl_httppost *form, void *arg,
+ curl_formget_callback append)
+{
+ (void) form;
+ (void) arg;
+ (void) append;
+ return CURL_FORMADD_DISABLED;
+}
+
+void curl_formfree(struct curl_httppost *form)
+{
+ (void)form;
+ /* does nothing HTTP is disabled */
+}
+
+
+#endif /* !defined(CURL_DISABLE_HTTP) */
diff --git a/libs/libcurl/src/formdata.h b/libs/libcurl/src/formdata.h
new file mode 100644
index 0000000000..22f504bb3d
--- /dev/null
+++ b/libs/libcurl/src/formdata.h
@@ -0,0 +1,98 @@
+#ifndef HEADER_CURL_FORMDATA_H
+#define HEADER_CURL_FORMDATA_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+
+enum formtype {
+ FORM_DATA, /* form metadata (convert to network encoding if necessary) */
+ FORM_CONTENT, /* form content (never convert) */
+ FORM_CALLBACK, /* 'line' points to the custom pointer we pass to the callback
+ */
+ FORM_FILE /* 'line' points to a file name we should read from
+ to create the form data (never convert) */
+};
+
+/* plain and simple linked list with lines to send */
+struct FormData {
+ struct FormData *next;
+ enum formtype type;
+ char *line;
+ size_t length;
+};
+
+struct Form {
+ struct FormData *data; /* current form line to send */
+ size_t sent; /* number of bytes of the current line that has
+ already been sent in a previous invoke */
+ FILE *fp; /* file to read from */
+ curl_read_callback fread_func; /* fread callback pointer */
+};
+
+/* used by FormAdd for temporary storage */
+typedef struct FormInfo {
+ char *name;
+ bool name_alloc;
+ size_t namelength;
+ char *value;
+ bool value_alloc;
+ size_t contentslength;
+ char *contenttype;
+ bool contenttype_alloc;
+ long flags;
+ char *buffer; /* pointer to existing buffer used for file upload */
+ size_t bufferlength;
+ char *showfilename; /* The file name to show. If not set, the actual
+ file name will be used */
+ bool showfilename_alloc;
+ char *userp; /* pointer for the read callback */
+ struct curl_slist* contentheader;
+ struct FormInfo *more;
+} FormInfo;
+
+int Curl_FormInit(struct Form *form, struct FormData *formdata );
+
+CURLcode Curl_getformdata(struct SessionHandle *data,
+ struct FormData **,
+ struct curl_httppost *post,
+ const char *custom_contenttype,
+ curl_off_t *size);
+
+/* fread() emulation */
+size_t Curl_FormReader(char *buffer,
+ size_t size,
+ size_t nitems,
+ FILE *mydata);
+
+/*
+ * Curl_formpostheader() returns the first line of the formpost, the
+ * request-header part (which is not part of the request-body like the rest of
+ * the post).
+ */
+char *Curl_formpostheader(void *formp, size_t *len);
+
+char *Curl_FormBoundary(void);
+
+void Curl_formclean(struct FormData **);
+
+CURLcode Curl_formconvert(struct SessionHandle *, struct FormData *);
+
+#endif /* HEADER_CURL_FORMDATA_H */
diff --git a/libs/libcurl/src/ftp.c b/libs/libcurl/src/ftp.c
new file mode 100644
index 0000000000..e818af6c58
--- /dev/null
+++ b/libs/libcurl/src/ftp.c
@@ -0,0 +1,4569 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_FTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "ftp.h"
+#include "fileinfo.h"
+#include "ftplistparser.h"
+#include "curl_sec.h"
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "inet_pton.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "speedcheck.h"
+#include "warnless.h"
+#include "http_proxy.h"
+#include "non-ascii.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"
+
+#ifndef NI_MAXHOST
+#define NI_MAXHOST 1025
+#endif
+#ifndef INET_ADDRSTRLEN
+#define INET_ADDRSTRLEN 16
+#endif
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define ftp_pasv_verbose(a,b,c,d) Curl_nop_stmt
+#endif
+
+/* Local API functions */
+#ifndef DEBUGBUILD
+static void _state(struct connectdata *conn,
+ ftpstate newstate);
+#define state(x,y) _state(x,y)
+#else
+static void _state(struct connectdata *conn,
+ ftpstate newstate,
+ int lineno);
+#define state(x,y) _state(x,y,__LINE__)
+#endif
+
+static CURLcode ftp_sendquote(struct connectdata *conn,
+ struct curl_slist *quote);
+static CURLcode ftp_quit(struct connectdata *conn);
+static CURLcode ftp_parse_url_path(struct connectdata *conn);
+static CURLcode ftp_regular_transfer(struct connectdata *conn, bool *done);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void ftp_pasv_verbose(struct connectdata *conn,
+ Curl_addrinfo *ai,
+ char *newhost, /* ascii version */
+ int port);
+#endif
+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,
+ bool ascii, ftpstate newstate);
+static int ftp_need_type(struct connectdata *conn,
+ bool ascii);
+static CURLcode ftp_do(struct connectdata *conn, bool *done);
+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, 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);
+static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode ftp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode ftp_setup_connection(struct connectdata * conn);
+
+static CURLcode init_wc_data(struct connectdata *conn);
+static CURLcode wc_statemach(struct connectdata *conn);
+
+static void wc_data_dtor(void *ptr);
+
+static CURLcode ftp_state_retr(struct connectdata *conn, curl_off_t filesize);
+
+static CURLcode ftp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *ftpcode,
+ size_t *size);
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+ bool connected);
+
+/* easy-to-use macro: */
+#define PPSENDF(x,y,z) if((result = Curl_pp_sendf(x,y,z)) != CURLE_OK) \
+ return result
+
+
+/*
+ * FTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftp = {
+ "FTP", /* scheme */
+ ftp_setup_connection, /* setup_connection */
+ ftp_do, /* do_it */
+ ftp_done, /* done */
+ ftp_do_more, /* do_more */
+ ftp_connect, /* connect_it */
+ ftp_multi_statemach, /* connecting */
+ ftp_doing, /* doing */
+ ftp_getsock, /* proto_getsock */
+ ftp_getsock, /* doing_getsock */
+ ftp_domore_getsock, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTP, /* defport */
+ CURLPROTO_FTP, /* protocol */
+ PROTOPT_DUAL | PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+#ifdef USE_SSL
+/*
+ * FTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ftps = {
+ "FTPS", /* scheme */
+ ftp_setup_connection, /* setup_connection */
+ ftp_do, /* do_it */
+ ftp_done, /* done */
+ ftp_do_more, /* do_more */
+ ftp_connect, /* connect_it */
+ ftp_multi_statemach, /* connecting */
+ ftp_doing, /* doing */
+ ftp_getsock, /* proto_getsock */
+ ftp_getsock, /* doing_getsock */
+ ftp_domore_getsock, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTPS, /* defport */
+ CURLPROTO_FTP | CURLPROTO_FTPS, /* protocol */
+ PROTOPT_SSL | PROTOPT_DUAL | PROTOPT_CLOSEACTION |
+ PROTOPT_NEEDSPWD | PROTOPT_NOURLQUERY /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed FTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftp_proxy = {
+ "FTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed FTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_ftps_proxy = {
+ "FTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_FTPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+
+/*
+ * NOTE: back in the old days, we added code in the FTP code that made NOBODY
+ * requests on files respond with headers passed to the client/stdout that
+ * looked like HTTP ones.
+ *
+ * This approach is not very elegant, it causes confusion and is error-prone.
+ * It is subject for removal at the next (or at least a future) soname bump.
+ * Until then you can test the effects of the removal by undefining the
+ * following define named CURL_FTP_HTTPSTYLE_HEAD.
+ */
+#define CURL_FTP_HTTPSTYLE_HEAD 1
+
+static void freedirs(struct ftp_conn *ftpc)
+{
+ int i;
+ if(ftpc->dirs) {
+ for(i=0; i < ftpc->dirdepth; i++) {
+ if(ftpc->dirs[i]) {
+ free(ftpc->dirs[i]);
+ ftpc->dirs[i]=NULL;
+ }
+ }
+ free(ftpc->dirs);
+ ftpc->dirs = NULL;
+ ftpc->dirdepth = 0;
+ }
+ if(ftpc->file) {
+ free(ftpc->file);
+ ftpc->file = NULL;
+ }
+}
+
+/* Returns non-zero if the given string contains CR (\r) or LF (\n),
+ which are not allowed within RFC 959 <string>.
+ Note: The input string is in the client's encoding which might
+ not be ASCII, so escape sequences \r & \n must be used instead
+ of hex values 0x0d & 0x0a.
+*/
+static bool isBadFtpString(const char *string)
+{
+ return ((NULL != strchr(string, '\r')) ||
+ (NULL != strchr(string, '\n'))) ? TRUE : FALSE;
+}
+
+/***********************************************************************
+ *
+ * AcceptServerConnect()
+ *
+ * After connection request is received from the server this function is
+ * called to accept the connection and close the listening socket
+ *
+ */
+static CURLcode AcceptServerConnect(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sock = conn->sock[SECONDARYSOCKET];
+ curl_socket_t s = CURL_SOCKET_BAD;
+#ifdef ENABLE_IPV6
+ struct Curl_sockaddr_storage add;
+#else
+ struct sockaddr_in add;
+#endif
+ curl_socklen_t size = (curl_socklen_t) sizeof(add);
+
+ if(0 == getsockname(sock, (struct sockaddr *) &add, &size)) {
+ size = sizeof(add);
+
+ s=accept(sock, (struct sockaddr *) &add, &size);
+ }
+ Curl_closesocket(conn, sock); /* close the first socket */
+
+ if(CURL_SOCKET_BAD == s) {
+ failf(data, "Error accept()ing server connect");
+ return CURLE_FTP_PORT_FAILED;
+ }
+ infof(data, "Connection accepted from server\n");
+
+ conn->sock[SECONDARYSOCKET] = s;
+ curlx_nonblock(s, TRUE); /* enable non-blocking */
+ conn->sock_accepted[SECONDARYSOCKET] = TRUE;
+
+ if(data->set.fsockopt) {
+ int error = 0;
+
+ /* activate callback for setting socket options */
+ error = data->set.fsockopt(data->set.sockopt_client,
+ s,
+ CURLSOCKTYPE_ACCEPT);
+
+ if(error) {
+ Curl_closesocket(conn, s); /* close the socket and bail out */
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+
+ return CURLE_OK;
+
+}
+
+/*
+ * ftp_timeleft_accept() returns the amount of milliseconds left allowed for
+ * waiting server to connect. If the value is negative, the timeout time has
+ * already elapsed.
+ *
+ * The start time is stored in progress.t_acceptdata - as set with
+ * Curl_pgrsTime(..., TIMER_STARTACCEPT);
+ *
+ */
+static long ftp_timeleft_accept(struct SessionHandle *data)
+{
+ long timeout_ms = DEFAULT_ACCEPT_TIMEOUT;
+ long other;
+ struct timeval now;
+
+ if(data->set.accepttimeout > 0)
+ timeout_ms = data->set.accepttimeout;
+
+ now = Curl_tvnow();
+
+ /* check if the generic timeout possibly is set shorter */
+ other = Curl_timeleft(data, &now, FALSE);
+ if(other && (other < timeout_ms))
+ /* note that this also works fine for when other happens to be negative
+ due to it already having elapsed */
+ timeout_ms = other;
+ else {
+ /* subtract elapsed time */
+ timeout_ms -= Curl_tvdiff(now, data->progress.t_acceptdata);
+ if(!timeout_ms)
+ /* avoid returning 0 as that means no timeout! */
+ return -1;
+ }
+
+ return timeout_ms;
+}
+
+
+/***********************************************************************
+ *
+ * ReceivedServerConnect()
+ *
+ * After allowing server to connect to us from data port, this function
+ * checks both data connection for connection establishment and ctrl
+ * connection for a negative response regarding a failure in connecting
+ *
+ */
+static CURLcode ReceivedServerConnect(struct connectdata *conn, bool *received)
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t ctrl_sock = conn->sock[FIRSTSOCKET];
+ curl_socket_t data_sock = conn->sock[SECONDARYSOCKET];
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ int result;
+ long timeout_ms;
+ ssize_t nread;
+ int ftpcode;
+
+ *received = FALSE;
+
+ timeout_ms = ftp_timeleft_accept(data);
+ infof(data, "Checking for server connect\n");
+ if(timeout_ms < 0) {
+ /* if a timeout was already reached, bail out */
+ failf(data, "Accept timeout occurred while waiting server connect");
+ return CURLE_FTP_ACCEPT_TIMEOUT;
+ }
+
+ /* First check whether there is a cached response from server */
+ if(pp->cache_size && pp->cache && pp->cache[0] > '3') {
+ /* Data connection could not be established, let's return */
+ infof(data, "There is negative response in cache while serv connect\n");
+ Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ return CURLE_FTP_ACCEPT_FAILED;
+ }
+
+ result = Curl_socket_check(ctrl_sock, data_sock, CURL_SOCKET_BAD, 0);
+
+ /* see if the connection request is already here */
+ switch (result) {
+ case -1: /* error */
+ /* let's die here */
+ failf(data, "Error while waiting for server connect");
+ return CURLE_FTP_ACCEPT_FAILED;
+ case 0: /* Server connect is not received yet */
+ break; /* loop */
+ default:
+
+ if(result & CURL_CSELECT_IN2) {
+ infof(data, "Ready to accept data connection from server\n");
+ *received = TRUE;
+ }
+ else if(result & CURL_CSELECT_IN) {
+ infof(data, "Ctrl conn has data while waiting for data conn\n");
+ Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ if(ftpcode/100 > 3)
+ return CURLE_FTP_ACCEPT_FAILED;
+
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+
+ break;
+ } /* switch() */
+
+ return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * InitiateTransfer()
+ *
+ * After connection from server is accepted this function is called to
+ * setup transfer parameters and initiate the data transfer.
+ *
+ */
+static CURLcode InitiateTransfer(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ CURLcode result = CURLE_OK;
+
+ if(conn->ssl[SECONDARYSOCKET].use) {
+ /* since we only have a plaintext TCP connection here, we must now
+ * do the TLS stuff */
+ infof(data, "Doing the SSL/TLS handshake on the data stream\n");
+ result = Curl_ssl_connect(conn, SECONDARYSOCKET);
+ if(result)
+ return result;
+ }
+
+ if(conn->proto.ftpc.state_saved == FTP_STOR) {
+ *(ftp->bytecountp)=0;
+
+ /* When we know we're uploading a specified file, we can get the file
+ size prior to the actual upload. */
+
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+ /* set the SO_SNDBUF for the secondary socket for those who need it */
+ Curl_sndbufset(conn->sock[SECONDARYSOCKET]);
+
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+ SECONDARYSOCKET, ftp->bytecountp);
+ }
+ else {
+ /* FTP download: */
+ Curl_setup_transfer(conn, SECONDARYSOCKET,
+ conn->proto.ftpc.retr_size_saved, FALSE,
+ ftp->bytecountp, -1, NULL); /* no upload here */
+ }
+
+ conn->proto.ftpc.pp.pending_resp = TRUE; /* expect server response */
+ state(conn, FTP_STOP);
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * AllowServerConnect()
+ *
+ * When we've issue the PORT command, we have told the server to connect to
+ * us. This function checks whether data connection is established if so it is
+ * accepted.
+ *
+ */
+static CURLcode AllowServerConnect(struct connectdata *conn, bool *connected)
+{
+ struct SessionHandle *data = conn->data;
+ long timeout_ms;
+ CURLcode ret = CURLE_OK;
+
+ *connected = FALSE;
+ infof(data, "Preparing for accepting server on data port\n");
+
+ /* Save the time we start accepting server connect */
+ Curl_pgrsTime(data, TIMER_STARTACCEPT);
+
+ timeout_ms = ftp_timeleft_accept(data);
+ if(timeout_ms < 0) {
+ /* if a timeout was already reached, bail out */
+ failf(data, "Accept timeout occurred while waiting server connect");
+ return CURLE_FTP_ACCEPT_TIMEOUT;
+ }
+
+ /* see if the connection request is already here */
+ ret = ReceivedServerConnect(conn, connected);
+ if(ret)
+ return ret;
+
+ if(*connected) {
+ ret = AcceptServerConnect(conn);
+ if(ret)
+ return ret;
+
+ ret = InitiateTransfer(conn);
+ if(ret)
+ return ret;
+ }
+ else {
+ /* Add timeout to multi handle and break out of the loop */
+ if(ret == CURLE_OK && *connected == FALSE) {
+ if(data->set.accepttimeout > 0)
+ Curl_expire(data, data->set.accepttimeout);
+ else
+ Curl_expire(data, DEFAULT_ACCEPT_TIMEOUT);
+ }
+ }
+
+ return ret;
+}
+
+/* macro to check for a three-digit ftp status code at the start of the
+ given string */
+#define STATUSCODE(line) (ISDIGIT(line[0]) && ISDIGIT(line[1]) && \
+ ISDIGIT(line[2]))
+
+/* macro to check for the last line in an FTP server response */
+#define LASTLINE(line) (STATUSCODE(line) && (' ' == line[3]))
+
+static bool ftp_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *code)
+{
+ (void)conn;
+
+ if((len > 3) && LASTLINE(line)) {
+ *code = curlx_sltosi(strtol(line, NULL, 10));
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static CURLcode ftp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *ftpcode, /* return the ftp-code if done */
+ size_t *size) /* size of the response */
+{
+ struct connectdata *conn = pp->conn;
+ struct SessionHandle *data = conn->data;
+#ifdef HAVE_GSSAPI
+ char * const buf = data->state.buffer;
+#endif
+ CURLcode result = CURLE_OK;
+ int code;
+
+ result = Curl_pp_readresp(sockfd, pp, &code, size);
+
+#if defined(HAVE_GSSAPI)
+ /* handle the security-oriented responses 6xx ***/
+ /* FIXME: some errorchecking perhaps... ***/
+ switch(code) {
+ case 631:
+ code = Curl_sec_read_msg(conn, buf, PROT_SAFE);
+ break;
+ case 632:
+ code = Curl_sec_read_msg(conn, buf, PROT_PRIVATE);
+ break;
+ case 633:
+ code = Curl_sec_read_msg(conn, buf, PROT_CONFIDENTIAL);
+ break;
+ default:
+ /* normal ftp stuff we pass through! */
+ break;
+ }
+#endif
+
+ /* store the latest code for later retrieval */
+ data->info.httpcode=code;
+
+ if(ftpcode)
+ *ftpcode = code;
+
+ if(421 == code) {
+ /* 421 means "Service not available, closing control connection." and FTP
+ * servers use it to signal that idle session timeout has been exceeded.
+ * If we ignored the response, it could end up hanging in some cases.
+ *
+ * This response code can come at any point so having it treated
+ * generically is a good idea.
+ */
+ infof(data, "We got a 421 - timeout!\n");
+ state(conn, FTP_STOP);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ return result;
+}
+
+/* --- parse FTP server responses --- */
+
+/*
+ * Curl_GetFTPResponse() is a BLOCKING function to read the full response
+ * from a server after a command.
+ *
+ */
+
+CURLcode Curl_GetFTPResponse(ssize_t *nreadp, /* return number of bytes read */
+ struct connectdata *conn,
+ int *ftpcode) /* return the ftp-code */
+{
+ /*
+ * We cannot read just one byte per read() and then go back to select() as
+ * the OpenSSL read() doesn't grok that properly.
+ *
+ * Alas, read as much as possible, split up into lines, use the ending
+ * line in a response or continue reading. */
+
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+ long timeout; /* timeout in milliseconds */
+ long interval_ms;
+ struct SessionHandle *data = conn->data;
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ size_t nread;
+ int cache_skip=0;
+ int value_to_be_ignored=0;
+
+ if(ftpcode)
+ *ftpcode = 0; /* 0 for errors */
+ else
+ /* make the pointer point to something for the rest of this function */
+ ftpcode = &value_to_be_ignored;
+
+ *nreadp=0;
+
+ while(!*ftpcode && !result) {
+ /* check and reset timeout value every lap */
+ timeout = Curl_pp_state_timeout(pp);
+
+ if(timeout <=0 ) {
+ failf(data, "FTP response timeout");
+ return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+ }
+
+ interval_ms = 1000; /* use 1 second timeout intervals */
+ if(timeout < interval_ms)
+ interval_ms = timeout;
+
+ /*
+ * Since this function is blocking, we need to wait here for input on the
+ * connection and only then we call the response reading function. We do
+ * timeout at least every second to make the timeout check run.
+ *
+ * A caution here is that the ftp_readresp() function has a cache that may
+ * contain pieces of a response from the previous invoke and we need to
+ * make sure we don't just wait for input while there is unhandled data in
+ * that cache. But also, if the cache is there, we call ftp_readresp() and
+ * the cache wasn't good enough to continue we must not just busy-loop
+ * around this function.
+ *
+ */
+
+ if(pp->cache && (cache_skip < 2)) {
+ /*
+ * There's a cache left since before. We then skipping the wait for
+ * socket action, unless this is the same cache like the previous round
+ * as then the cache was deemed not enough to act on and we then need to
+ * wait for more data anyway.
+ */
+ }
+ else {
+ switch (Curl_socket_ready(sockfd, CURL_SOCKET_BAD, interval_ms)) {
+ case -1: /* select() error, stop reading */
+ failf(data, "FTP response aborted due to select/poll error: %d",
+ SOCKERRNO);
+ return CURLE_RECV_ERROR;
+
+ case 0: /* timeout */
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ continue; /* just continue in our loop for the timeout duration */
+
+ default: /* for clarity */
+ break;
+ }
+ }
+ result = ftp_readresp(sockfd, pp, ftpcode, &nread);
+ if(result)
+ break;
+
+ if(!nread && pp->cache)
+ /* bump cache skip counter as on repeated skips we must wait for more
+ data */
+ cache_skip++;
+ else
+ /* when we got data or there is no cache left, we reset the cache skip
+ counter */
+ cache_skip=0;
+
+ *nreadp += nread;
+
+ } /* while there's buffer left and loop is requested */
+
+ pp->pending_resp = FALSE;
+
+ return result;
+}
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+static const char * const ftp_state_names[]={
+ "STOP",
+ "WAIT220",
+ "AUTH",
+ "USER",
+ "PASS",
+ "ACCT",
+ "PBSZ",
+ "PROT",
+ "CCC",
+ "PWD",
+ "SYST",
+ "NAMEFMT",
+ "QUOTE",
+ "RETR_PREQUOTE",
+ "STOR_PREQUOTE",
+ "POSTQUOTE",
+ "CWD",
+ "MKD",
+ "MDTM",
+ "TYPE",
+ "LIST_TYPE",
+ "RETR_TYPE",
+ "STOR_TYPE",
+ "SIZE",
+ "RETR_SIZE",
+ "STOR_SIZE",
+ "REST",
+ "RETR_REST",
+ "PORT",
+ "PRET",
+ "PASV",
+ "LIST",
+ "RETR",
+ "STOR",
+ "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",
+ (void *)ftpc, lineno, ftp_state_names[ftpc->state],
+ ftp_state_names[newstate]);
+#endif
+ ftpc->state = newstate;
+}
+
+static CURLcode ftp_state_user(struct connectdata *conn)
+{
+ CURLcode result;
+ struct FTP *ftp = conn->data->req.protop;
+ /* send USER */
+ PPSENDF(&conn->proto.ftpc.pp, "USER %s", ftp->user?ftp->user:"");
+
+ state(conn, FTP_USER);
+ conn->data->state.ftp_trying_alternative = FALSE;
+
+ return CURLE_OK;
+}
+
+static CURLcode ftp_state_pwd(struct connectdata *conn)
+{
+ CURLcode result;
+
+ /* send PWD to discover our entry point */
+ PPSENDF(&conn->proto.ftpc.pp, "%s", "PWD");
+ state(conn, FTP_PWD);
+
+ return CURLE_OK;
+}
+
+/* For the FTP "protocol connect" and "doing" phases only */
+static int ftp_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.ftpc.pp, socks, numsocks);
+}
+
+/* For the FTP "DO_MORE" phase only */
+static int ftp_domore_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(!numsocks)
+ 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.
+ */
+
+ 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);
+}
+
+/* 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
+ the correct directory. It may also need to send MKD commands to create
+ missing ones, if that option is enabled.
+*/
+static CURLcode ftp_state_cwd(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(ftpc->cwddone)
+ /* already done and fine */
+ result = ftp_state_mdtm(conn);
+ else {
+ ftpc->count2 = 0; /* count2 counts failed CWDs */
+
+ /* count3 is set to allow a MKD to fail once. In the case when first CWD
+ fails and then MKD fails (due to another session raced it to create the
+ dir) this then allows for a second try to CWD to it */
+ ftpc->count3 = (conn->data->set.ftp_create_missing_dirs==2)?1:0;
+
+ if(conn->bits.reuse && ftpc->entrypath) {
+ /* This is a re-used connection. Since we change directory to where the
+ transfer is taking place, we must first get back to the original dir
+ where we ended up after login: */
+ ftpc->count1 = 0; /* we count this as the first path, then we add one
+ for all upcoming ones in the ftp->dirs[] array */
+ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->entrypath);
+ state(conn, FTP_CWD);
+ }
+ else {
+ if(ftpc->dirdepth) {
+ ftpc->count1 = 1;
+ /* issue the first CWD, the rest is sent when the CWD responses are
+ received... */
+ PPSENDF(&conn->proto.ftpc.pp, "CWD %s", ftpc->dirs[ftpc->count1 -1]);
+ state(conn, FTP_CWD);
+ }
+ else {
+ /* No CWD necessary */
+ result = ftp_state_mdtm(conn);
+ }
+ }
+ }
+ return result;
+}
+
+typedef enum {
+ EPRT,
+ PORT,
+ DONE
+} ftpport;
+
+static CURLcode ftp_state_use_port(struct connectdata *conn,
+ ftpport fcmd) /* start with this */
+
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct SessionHandle *data=conn->data;
+ curl_socket_t portsock= CURL_SOCKET_BAD;
+ char myhost[256] = "";
+
+ struct Curl_sockaddr_storage ss;
+ Curl_addrinfo *res, *ai;
+ curl_socklen_t sslen;
+ char hbuf[NI_MAXHOST];
+ struct sockaddr *sa=(struct sockaddr *)&ss;
+ struct sockaddr_in * const sa4 = (void *)sa;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 * const sa6 = (void *)sa;
+#endif
+ char tmp[1024];
+ static const char mode[][5] = { "EPRT", "PORT" };
+ int rc;
+ int error;
+ char *host = NULL;
+ char *string_ftpport = data->set.str[STRING_FTPPORT];
+ struct Curl_dns_entry *h=NULL;
+ unsigned short port_min = 0;
+ unsigned short port_max = 0;
+ unsigned short port;
+ bool possibly_non_local = TRUE;
+
+ char *addr = NULL;
+
+ /* Step 1, figure out what is requested,
+ * accepted format :
+ * (ipv4|ipv6|domain|interface)?(:port(-range)?)?
+ */
+
+ if(data->set.str[STRING_FTPPORT] &&
+ (strlen(data->set.str[STRING_FTPPORT]) > 1)) {
+
+#ifdef ENABLE_IPV6
+ size_t addrlen = INET6_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET6_ADDRSTRLEN : strlen(string_ftpport);
+#else
+ size_t addrlen = INET_ADDRSTRLEN > strlen(string_ftpport) ?
+ INET_ADDRSTRLEN : strlen(string_ftpport);
+#endif
+ char *ip_start = string_ftpport;
+ char *ip_end = NULL;
+ char *port_start = NULL;
+ char *port_sep = NULL;
+
+ addr = calloc(addrlen+1, 1);
+ if(!addr)
+ return CURLE_OUT_OF_MEMORY;
+
+#ifdef ENABLE_IPV6
+ if(*string_ftpport == '[') {
+ /* [ipv6]:port(-range) */
+ ip_start = string_ftpport + 1;
+ if((ip_end = strchr(string_ftpport, ']')) != NULL )
+ strncpy(addr, ip_start, ip_end - ip_start);
+ }
+ else
+#endif
+ if(*string_ftpport == ':') {
+ /* :port */
+ ip_end = string_ftpport;
+ }
+ else if((ip_end = strchr(string_ftpport, ':')) != NULL) {
+ /* either ipv6 or (ipv4|domain|interface):port(-range) */
+#ifdef ENABLE_IPV6
+ if(Curl_inet_pton(AF_INET6, string_ftpport, sa6) == 1) {
+ /* ipv6 */
+ port_min = port_max = 0;
+ strcpy(addr, string_ftpport);
+ ip_end = NULL; /* this got no port ! */
+ }
+ else
+#endif
+ /* (ipv4|domain|interface):port(-range) */
+ strncpy(addr, string_ftpport, ip_end - ip_start );
+ }
+ else
+ /* ipv4|interface */
+ strcpy(addr, string_ftpport);
+
+ /* parse the port */
+ if(ip_end != NULL) {
+ if((port_start = strchr(ip_end, ':')) != NULL) {
+ port_min = curlx_ultous(strtoul(port_start+1, NULL, 10));
+ if((port_sep = strchr(port_start, '-')) != NULL) {
+ port_max = curlx_ultous(strtoul(port_sep + 1, NULL, 10));
+ }
+ else
+ port_max = port_min;
+ }
+ }
+
+ /* correct errors like:
+ * :1234-1230
+ * :-4711 , in this case port_min is (unsigned)-1,
+ * therefore port_min > port_max for all cases
+ * but port_max = (unsigned)-1
+ */
+ if(port_min > port_max )
+ port_min = port_max = 0;
+
+
+ if(*addr != '\0') {
+ /* attempt to get the address of the given interface name */
+ switch(Curl_if2ip(conn->ip_addr->ai_family, conn->scope, addr,
+ hbuf, sizeof(hbuf))) {
+ case IF2IP_NOT_FOUND:
+ /* not an interface, use the given string as host name instead */
+ host = addr;
+ break;
+ case IF2IP_AF_NOT_SUPPORTED:
+ return CURLE_FTP_PORT_FAILED;
+ case IF2IP_FOUND:
+ host = hbuf; /* use the hbuf for host name */
+ }
+ }
+ else
+ /* there was only a port(-range) given, default the host */
+ host = NULL;
+ } /* data->set.ftpport */
+
+ if(!host) {
+ /* not an interface and not a host name, get default by extracting
+ the IP from the control connection */
+
+ sslen = sizeof(ss);
+ if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ Curl_safefree(addr);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ switch(sa->sa_family) {
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ Curl_inet_ntop(sa->sa_family, &sa6->sin6_addr, hbuf, sizeof(hbuf));
+ break;
+#endif
+ default:
+ Curl_inet_ntop(sa->sa_family, &sa4->sin_addr, hbuf, sizeof(hbuf));
+ break;
+ }
+ host = hbuf; /* use this host name */
+ possibly_non_local = FALSE; /* we know it is local now */
+ }
+
+ /* resolv ip/host to ip */
+ rc = Curl_resolv(conn, host, 0, &h);
+ if(rc == CURLRESOLV_PENDING)
+ (void)Curl_resolver_wait_resolv(conn, &h);
+ if(h) {
+ res = h->addr;
+ /* when we return from this function, we can forget about this entry
+ to we can unlock it now already */
+ Curl_resolv_unlock(data, h);
+ } /* (h) */
+ else
+ res = NULL; /* failure! */
+
+ if(res == NULL) {
+ failf(data, "failed to resolve the address provided to PORT: %s", host);
+ Curl_safefree(addr);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ Curl_safefree(addr);
+ host = NULL;
+
+ /* step 2, create a socket for the requested address */
+
+ portsock = CURL_SOCKET_BAD;
+ error = 0;
+ for(ai = res; ai; ai = ai->ai_next) {
+ result = Curl_socket(conn, ai, NULL, &portsock);
+ if(result) {
+ error = SOCKERRNO;
+ continue;
+ }
+ break;
+ }
+ if(!ai) {
+ failf(data, "socket failure: %s", Curl_strerror(conn, error));
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 3, bind to a suitable local address */
+
+ memcpy(sa, ai->ai_addr, ai->ai_addrlen);
+ sslen = ai->ai_addrlen;
+
+ for(port = port_min; port <= port_max;) {
+ if(sa->sa_family == AF_INET)
+ sa4->sin_port = htons(port);
+#ifdef ENABLE_IPV6
+ else
+ sa6->sin6_port = htons(port);
+#endif
+ /* Try binding the given address. */
+ if(bind(portsock, sa, sslen) ) {
+ /* It failed. */
+ error = SOCKERRNO;
+ if(possibly_non_local && (error == EADDRNOTAVAIL)) {
+ /* The requested bind address is not local. Use the address used for
+ * the control connection instead and restart the port loop
+ */
+
+ infof(data, "bind(port=%hu) on non-local address failed: %s\n", port,
+ Curl_strerror(conn, error) );
+
+ sslen = sizeof(ss);
+ if(getsockname(conn->sock[FIRSTSOCKET], sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ port = port_min;
+ possibly_non_local = FALSE; /* don't try this again */
+ continue;
+ }
+ else if(error != EADDRINUSE && error != EACCES) {
+ failf(data, "bind(port=%hu) failed: %s", port,
+ Curl_strerror(conn, error) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+ }
+ else
+ break;
+
+ port++;
+ }
+
+ /* maybe all ports were in use already*/
+ if(port > port_max) {
+ failf(data, "bind() failed, we ran out of ports!");
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* get the name again after the bind() so that we can extract the
+ port number it uses now */
+ sslen = sizeof(ss);
+ if(getsockname(portsock, (struct sockaddr *)sa, &sslen)) {
+ failf(data, "getsockname() failed: %s",
+ Curl_strerror(conn, SOCKERRNO) );
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 4, listen on the socket */
+
+ if(listen(portsock, 1)) {
+ failf(data, "socket failure: %s", Curl_strerror(conn, SOCKERRNO));
+ Curl_closesocket(conn, portsock);
+ return CURLE_FTP_PORT_FAILED;
+ }
+
+ /* step 5, send the proper FTP command */
+
+ /* get a plain printable version of the numerical address to work with
+ below */
+ Curl_printable_address(ai, myhost, sizeof(myhost));
+
+#ifdef ENABLE_IPV6
+ if(!conn->bits.ftp_use_eprt && conn->bits.ipv6)
+ /* EPRT is disabled but we are connected to a IPv6 host, so we ignore the
+ request and enable EPRT again! */
+ conn->bits.ftp_use_eprt = TRUE;
+#endif
+
+ for(; fcmd != DONE; fcmd++) {
+
+ if(!conn->bits.ftp_use_eprt && (EPRT == fcmd))
+ /* if disabled, goto next */
+ continue;
+
+ if((PORT == fcmd) && sa->sa_family != AF_INET)
+ /* PORT is ipv4 only */
+ continue;
+
+ switch (sa->sa_family) {
+ case AF_INET:
+ port = ntohs(sa4->sin_port);
+ break;
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ port = ntohs(sa6->sin6_port);
+ break;
+#endif
+ default:
+ continue; /* might as well skip this */
+ }
+
+ if(EPRT == fcmd) {
+ /*
+ * Two fine examples from RFC2428;
+ *
+ * EPRT |1|132.235.1.2|6275|
+ *
+ * EPRT |2|1080::8:800:200C:417A|5282|
+ */
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s |%d|%s|%hu|", mode[fcmd],
+ sa->sa_family == AF_INET?1:2,
+ myhost, port);
+ if(result) {
+ failf(data, "Failure sending EPRT command: %s",
+ curl_easy_strerror(result));
+ Curl_closesocket(conn, portsock);
+ /* don't retry using PORT */
+ ftpc->count1 = PORT;
+ /* bail out */
+ state(conn, FTP_STOP);
+ return result;
+ }
+ break;
+ }
+ else if(PORT == fcmd) {
+ char *source = myhost;
+ char *dest = tmp;
+
+ /* translate x.x.x.x to x,x,x,x */
+ while(source && *source) {
+ if(*source == '.')
+ *dest=',';
+ else
+ *dest = *source;
+ dest++;
+ source++;
+ }
+ *dest = 0;
+ snprintf(dest, 20, ",%d,%d", (int)(port>>8), (int)(port&0xff));
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s %s", mode[fcmd], tmp);
+ if(result) {
+ failf(data, "Failure sending PORT command: %s",
+ curl_easy_strerror(result));
+ Curl_closesocket(conn, portsock);
+ /* bail out */
+ state(conn, FTP_STOP);
+ return result;
+ }
+ break;
+ }
+ }
+
+ /* store which command was sent */
+ ftpc->count1 = fcmd;
+
+ /* we set the secondary socket variable to this for now, it is only so that
+ the cleanup function will close it in case we fail before the true
+ secondary stuff is made */
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = portsock;
+
+ /* this tcpconnect assignment below is a hackish work-around to make the
+ multi interface with active FTP work - as it will not wait for a
+ (passive) connect in Curl_is_connected().
+
+ The *proper* fix is to make sure that the active connection from the
+ server is done in a non-blocking way. Currently, it is still BLOCKING.
+ */
+ conn->bits.tcpconnect[SECONDARYSOCKET] = TRUE;
+
+ state(conn, FTP_PORT);
+ return result;
+}
+
+static CURLcode ftp_state_use_pasv(struct connectdata *conn)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result = CURLE_OK;
+ /*
+ Here's the excecutive summary on what to do:
+
+ PASV is RFC959, expect:
+ 227 Entering Passive Mode (a1,a2,a3,a4,p1,p2)
+
+ LPSV is RFC1639, expect:
+ 228 Entering Long Passive Mode (4,4,a1,a2,a3,a4,2,p1,p2)
+
+ EPSV is RFC2428, expect:
+ 229 Entering Extended Passive Mode (|||port|)
+
+ */
+
+ static const char mode[][5] = { "EPSV", "PASV" };
+ int modeoff;
+
+#ifdef PF_INET6
+ if(!conn->bits.ftp_use_epsv && conn->bits.ipv6)
+ /* EPSV is disabled but we are connected to a IPv6 host, so we ignore the
+ request and enable EPSV again! */
+ conn->bits.ftp_use_epsv = TRUE;
+#endif
+
+ modeoff = conn->bits.ftp_use_epsv?0:1;
+
+ PPSENDF(&ftpc->pp, "%s", mode[modeoff]);
+
+ ftpc->count1 = modeoff;
+ state(conn, FTP_PASV);
+ infof(conn->data, "Connect data stream passively\n");
+
+ return result;
+}
+
+/*
+ * 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->req.protop;
+ struct SessionHandle *data = conn->data;
+
+ if(ftp->transfer != FTPTRANSFER_BODY) {
+ /* doesn't transfer any data */
+
+ /* still possibly do PRE QUOTE jobs */
+ state(conn, FTP_RETR_PREQUOTE);
+ result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+ }
+ else if(data->set.ftp_use_port) {
+ /* We have chosen to use the PORT (or similar) command */
+ result = ftp_state_use_port(conn, EPRT);
+ }
+ else {
+ /* We have chosen (this is default) to use the PASV (or similar) command */
+ if(data->set.ftp_use_pret) {
+ /* The user has requested that we send a PRET command
+ to prepare the server for the upcoming PASV */
+ if(!conn->proto.ftpc.file) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET %s",
+ data->set.str[STRING_CUSTOMREQUEST]?
+ data->set.str[STRING_CUSTOMREQUEST]:
+ (data->set.ftp_list_only?"NLST":"LIST"));
+ }
+ else if(data->set.upload) {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET STOR %s", conn->proto.ftpc.file);
+ }
+ else {
+ PPSENDF(&conn->proto.ftpc.pp, "PRET RETR %s", conn->proto.ftpc.file);
+ }
+ state(conn, FTP_PRET);
+ }
+ else {
+ result = ftp_state_use_pasv(conn);
+ }
+ }
+ return result;
+}
+
+static CURLcode ftp_state_rest(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer != FTPTRANSFER_BODY) && ftpc->file) {
+ /* if a "head"-like request is being made (on a file) */
+
+ /* Determine if server can respond to REST command and therefore
+ whether it supports range */
+ PPSENDF(&conn->proto.ftpc.pp, "REST %d", 0);
+
+ state(conn, FTP_REST);
+ }
+ else
+ result = ftp_state_prepare_transfer(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_size(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if((ftp->transfer == FTPTRANSFER_INFO) && ftpc->file) {
+ /* if a "head"-like request is being made (on a file) */
+
+ /* we know ftpc->file is a valid pointer to a file name */
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+
+ state(conn, FTP_SIZE);
+ }
+ else
+ result = ftp_state_rest(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_list(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ /* If this output is to be machine-parsed, the NLST command might be better
+ to use, since the LIST command output is not specified or standard in any
+ way. It has turned out that the NLST list output is not the same on all
+ servers either... */
+
+ /*
+ if FTPFILE_NOCWD was specified, we are currently in
+ the user's home directory, so we should add the path
+ as argument for the LIST / NLST / or custom command.
+ Whether the server will support this, is uncertain.
+
+ The other ftp_filemethods will CWD into dir/dir/ first and
+ then just do LIST (in that case: nothing to do here)
+ */
+ char *cmd,*lstArg,*slashPos;
+
+ lstArg = NULL;
+ if((data->set.ftp_filemethod == FTPFILE_NOCWD) &&
+ data->state.path &&
+ data->state.path[0] &&
+ strchr(data->state.path,'/')) {
+
+ lstArg = strdup(data->state.path);
+ if(!lstArg)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Check if path does not end with /, as then we cut off the file part */
+ if(lstArg[strlen(lstArg) - 1] != '/') {
+
+ /* chop off the file part if format is dir/dir/file */
+ slashPos = strrchr(lstArg,'/');
+ if(slashPos)
+ *(slashPos+1) = '\0';
+ }
+ }
+
+ cmd = aprintf( "%s%s%s",
+ data->set.str[STRING_CUSTOMREQUEST]?
+ data->set.str[STRING_CUSTOMREQUEST]:
+ (data->set.ftp_list_only?"NLST":"LIST"),
+ lstArg? " ": "",
+ lstArg? lstArg: "" );
+
+ if(!cmd) {
+ if(lstArg)
+ free(lstArg);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result = Curl_pp_sendf(&conn->proto.ftpc.pp, "%s", cmd);
+
+ if(lstArg)
+ free(lstArg);
+
+ free(cmd);
+
+ if(result != CURLE_OK)
+ return result;
+
+ state(conn, FTP_LIST);
+
+ return result;
+}
+
+static CURLcode ftp_state_retr_prequote(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* We've sent the TYPE, now we must send the list of prequote strings */
+
+ result = ftp_state_quote(conn, TRUE, FTP_RETR_PREQUOTE);
+
+ return result;
+}
+
+static CURLcode ftp_state_stor_prequote(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* We've sent the TYPE, now we must send the list of prequote strings */
+
+ result = ftp_state_quote(conn, TRUE, FTP_STOR_PREQUOTE);
+
+ return result;
+}
+
+static CURLcode ftp_state_type(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ /* If we have selected NOBODY and HEADER, it means that we only want file
+ information. Which in FTP can't be much more than the file size and
+ date. */
+ if(data->set.opt_no_body && ftpc->file &&
+ ftp_need_type(conn, data->set.prefer_ascii)) {
+ /* The SIZE command is _not_ RFC 959 specified, and therefor many servers
+ may not support it! It is however the only way we have to get a file's
+ size! */
+
+ ftp->transfer = FTPTRANSFER_INFO;
+ /* this means no actual transfer will be made */
+
+ /* Some servers return different sizes for different modes, and thus we
+ must set the proper type before we check the size */
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_TYPE);
+ if(result)
+ return result;
+ }
+ else
+ 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_mdtm(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ /* Requested time of file or time-depended transfer? */
+ if((data->set.get_filetime || data->set.timecondition) && ftpc->file) {
+
+ /* we have requested to get the modified-time of the file, this is a white
+ spot as the MDTM is not mentioned in RFC959 */
+ PPSENDF(&ftpc->pp, "MDTM %s", ftpc->file);
+
+ state(conn, FTP_MDTM);
+ }
+ else
+ result = ftp_state_type(conn);
+
+ return result;
+}
+
+
+/* This is called after the TYPE and possible quote commands have been sent */
+static CURLcode ftp_state_ul_setup(struct connectdata *conn,
+ bool sizechecked)
+{
+ CURLcode result = CURLE_OK;
+ struct FTP *ftp = conn->data->req.protop;
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ int seekerr = CURL_SEEKFUNC_OK;
+
+ if((data->state.resume_from && !sizechecked) ||
+ ((data->state.resume_from > 0) && sizechecked)) {
+ /* we're about to continue the uploading of a file */
+ /* 1. get already existing file's size. We use the SIZE command for this
+ which may not exist in the server! The SIZE command is not in
+ RFC959. */
+
+ /* 2. This used to set REST. But since we can do append, we
+ don't another ftp command. We just skip the source file
+ offset and then we APPEND the rest on the file instead */
+
+ /* 3. pass file-size number of bytes in the source file */
+ /* 4. lower the infilesize counter */
+ /* => transfer as usual */
+
+ if(data->state.resume_from < 0 ) {
+ /* Got no given size to start from, figure it out */
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+ state(conn, FTP_STOR_SIZE);
+ return result;
+ }
+
+ /* enable append */
+ data->set.ftp_append = TRUE;
+
+ /* Let's read off the proper amount of bytes from the input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ else {
+ curl_off_t passed=0;
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
+ BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ conn->fread_func(data->state.buffer, 1, readthisamountnow,
+ conn->fread_in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Failed to read data");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ } while(passed < data->state.resume_from);
+ }
+ }
+ /* now, decrease the size of the read */
+ if(data->set.infilesize>0) {
+ data->set.infilesize -= data->state.resume_from;
+
+ if(data->set.infilesize <= 0) {
+ infof(data, "File already completely uploaded\n");
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ /* Set ->transfer so that we won't get any error in
+ * ftp_done() because we didn't transfer anything! */
+ ftp->transfer = FTPTRANSFER_NONE;
+
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ }
+ /* we've passed, proceed as normal */
+ } /* resume_from */
+
+ PPSENDF(&ftpc->pp, data->set.ftp_append?"APPE %s":"STOR %s",
+ ftpc->file);
+
+ state(conn, FTP_STOR);
+
+ return result;
+}
+
+static CURLcode ftp_state_quote(struct connectdata *conn,
+ bool init,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ bool quote=FALSE;
+ struct curl_slist *item;
+
+ switch(instate) {
+ case FTP_QUOTE:
+ default:
+ item = data->set.quote;
+ break;
+ case FTP_RETR_PREQUOTE:
+ case FTP_STOR_PREQUOTE:
+ item = data->set.prequote;
+ break;
+ case FTP_POSTQUOTE:
+ item = data->set.postquote;
+ break;
+ }
+
+ /*
+ * This state uses:
+ * 'count1' to iterate over the commands to send
+ * 'count2' to store wether to allow commands to fail
+ */
+
+ if(init)
+ ftpc->count1 = 0;
+ else
+ ftpc->count1++;
+
+ if(item) {
+ int i = 0;
+
+ /* Skip count1 items in the linked list */
+ while((i< ftpc->count1) && item) {
+ item = item->next;
+ i++;
+ }
+ if(item) {
+ char *cmd = item->data;
+ if(cmd[0] == '*') {
+ cmd++;
+ ftpc->count2 = 1; /* the sent command is allowed to fail */
+ }
+ else
+ ftpc->count2 = 0; /* failure means cancel operation */
+
+ PPSENDF(&ftpc->pp, "%s", cmd);
+ state(conn, instate);
+ quote = TRUE;
+ }
+ }
+
+ if(!quote) {
+ /* No more quote to send, continue to ... */
+ switch(instate) {
+ case FTP_QUOTE:
+ default:
+ result = ftp_state_cwd(conn);
+ break;
+ case FTP_RETR_PREQUOTE:
+ if(ftp->transfer != FTPTRANSFER_BODY)
+ state(conn, FTP_STOP);
+ else {
+ if(ftpc->known_filesize != -1) {
+ Curl_pgrsSetDownloadSize(data, ftpc->known_filesize);
+ result = ftp_state_retr(conn, ftpc->known_filesize);
+ }
+ else {
+ PPSENDF(&ftpc->pp, "SIZE %s", ftpc->file);
+ state(conn, FTP_RETR_SIZE);
+ }
+ }
+ break;
+ case FTP_STOR_PREQUOTE:
+ result = ftp_state_ul_setup(conn, FALSE);
+ break;
+ case FTP_POSTQUOTE:
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* called from ftp_state_pasv_resp to switch to PASV in case of EPSV
+ problems */
+static CURLcode ftp_epsv_disable(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ 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, "%s", "PASV");
+ conn->proto.ftpc.count1++;
+ /* remain in/go to the FTP_PASV state */
+ state(conn, FTP_PASV);
+ return result;
+}
+
+static CURLcode ftp_state_pasv_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result;
+ struct SessionHandle *data=conn->data;
+ Curl_addrinfo *conninfo;
+ struct Curl_dns_entry *addr=NULL;
+ int rc;
+ unsigned short connectport; /* the local port connect() should use! */
+ unsigned short newport=0; /* remote port */
+ bool connected;
+
+ /* newhost must be able to hold a full IP-style address in ASCII, which
+ in the IPv6 case means 5*8-1 = 39 letters */
+#define NEWHOST_BUFSIZE 48
+ char newhost[NEWHOST_BUFSIZE];
+ char *str=&data->state.buffer[4]; /* start on the first letter */
+
+ if((ftpc->count1 == 0) &&
+ (ftpcode == 229)) {
+ /* positive EPSV response */
+ char *ptr = strchr(str, '(');
+ if(ptr) {
+ unsigned int num;
+ char separator[4];
+ ptr++;
+ if(5 == sscanf(ptr, "%c%c%c%u%c",
+ &separator[0],
+ &separator[1],
+ &separator[2],
+ &num,
+ &separator[3])) {
+ const char sep1 = separator[0];
+ int i;
+
+ /* The four separators should be identical, or else this is an oddly
+ formatted reply and we bail out immediately. */
+ for(i=1; i<4; i++) {
+ if(separator[i] != sep1) {
+ ptr=NULL; /* set to NULL to signal error */
+ break;
+ }
+ }
+ if(num > 0xffff) {
+ failf(data, "Illegal port number in EPSV reply");
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+ if(ptr) {
+ newport = (unsigned short)(num & 0xffff);
+
+ if(conn->bits.tunnel_proxy ||
+ conn->proxytype == CURLPROXY_SOCKS5 ||
+ conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+ conn->proxytype == CURLPROXY_SOCKS4 ||
+ conn->proxytype == CURLPROXY_SOCKS4A)
+ /* proxy tunnel -> use other host info because ip_addr_str is the
+ proxy address not the ftp host */
+ snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
+ else
+ /* use the same IP we are already connected to */
+ snprintf(newhost, NEWHOST_BUFSIZE, "%s", conn->ip_addr_str);
+ }
+ }
+ else
+ ptr=NULL;
+ }
+ if(!ptr) {
+ failf(data, "Weirdly formatted EPSV reply");
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+ }
+ else if((ftpc->count1 == 1) &&
+ (ftpcode == 227)) {
+ /* positive PASV response */
+ int ip[4];
+ int port[2];
+
+ /*
+ * Scan for a sequence of six comma-separated numbers and use them as
+ * IP+port indicators.
+ *
+ * Found reply-strings include:
+ * "227 Entering Passive Mode (127,0,0,1,4,51)"
+ * "227 Data transfer will passively listen to 127,0,0,1,4,51"
+ * "227 Entering passive mode. 127,0,0,1,4,51"
+ */
+ while(*str) {
+ if(6 == sscanf(str, "%d,%d,%d,%d,%d,%d",
+ &ip[0], &ip[1], &ip[2], &ip[3],
+ &port[0], &port[1]))
+ break;
+ str++;
+ }
+
+ if(!*str) {
+ failf(data, "Couldn't interpret the 227-response");
+ return CURLE_FTP_WEIRD_227_FORMAT;
+ }
+
+ /* we got OK from server */
+ if(data->set.ftp_skip_ip) {
+ /* told to ignore the remotely given IP but instead use the one we used
+ for the control connection */
+ infof(data, "Skips %d.%d.%d.%d for data connection, uses %s instead\n",
+ ip[0], ip[1], ip[2], ip[3],
+ conn->ip_addr_str);
+ if(conn->bits.tunnel_proxy ||
+ conn->proxytype == CURLPROXY_SOCKS5 ||
+ conn->proxytype == CURLPROXY_SOCKS5_HOSTNAME ||
+ conn->proxytype == CURLPROXY_SOCKS4 ||
+ conn->proxytype == CURLPROXY_SOCKS4A)
+ /* proxy tunnel -> use other host info because ip_addr_str is the
+ proxy address not the ftp host */
+ snprintf(newhost, sizeof(newhost), "%s", conn->host.name);
+ else
+ snprintf(newhost, sizeof(newhost), "%s", conn->ip_addr_str);
+ }
+ else
+ snprintf(newhost, sizeof(newhost),
+ "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]);
+ newport = (unsigned short)(((port[0]<<8) + port[1]) & 0xffff);
+ }
+ else if(ftpc->count1 == 0) {
+ /* EPSV failed, move on to PASV */
+ return ftp_epsv_disable(conn);
+ }
+ else {
+ failf(data, "Bad PASV/EPSV response: %03d", ftpcode);
+ return CURLE_FTP_WEIRD_PASV_REPLY;
+ }
+
+ if(conn->bits.proxy) {
+ /*
+ * 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)
+ /* BLOCKING, ignores the return code but 'addr' will be NULL in
+ case of failure */
+ (void)Curl_resolver_wait_resolv(conn, &addr);
+
+ connectport =
+ (unsigned short)conn->port; /* we connect to the proxy's port */
+
+ if(!addr) {
+ failf(data, "Can't resolve proxy host %s:%hu",
+ conn->proxy.name, connectport);
+ return CURLE_FTP_CANT_GET_HOST;
+ }
+ }
+ else {
+ /* normal, direct, ftp connection */
+ rc = Curl_resolv(conn, newhost, newport, &addr);
+ if(rc == CURLRESOLV_PENDING)
+ /* BLOCKING */
+ (void)Curl_resolver_wait_resolv(conn, &addr);
+
+ connectport = newport; /* we connect to the remote port */
+
+ if(!addr) {
+ failf(data, "Can't resolve new host %s:%hu", newhost, connectport);
+ return CURLE_FTP_CANT_GET_HOST;
+ }
+ }
+
+ result = Curl_connecthost(conn,
+ addr,
+ &conn->sock[SECONDARYSOCKET],
+ &conninfo,
+ &connected);
+
+ Curl_resolv_unlock(data, addr); /* we're done using this address */
+
+ if(result) {
+ if(ftpc->count1 == 0 && ftpcode == 229)
+ return ftp_epsv_disable(conn);
+
+ return result;
+ }
+
+ conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
+
+ /*
+ * When this is used from the multi interface, this might've returned with
+ * the 'connected' set to FALSE and thus we are now awaiting a non-blocking
+ * connect to connect and we should not be "hanging" here waiting.
+ */
+
+ if(data->set.verbose)
+ /* this just dumps information about this second connection */
+ ftp_pasv_verbose(conn, conninfo, newhost, connectport);
+
+ switch(conn->proxytype) {
+ /* FIX: this MUST wait for a proper connect first if 'connected' is
+ * FALSE */
+ case CURLPROXY_SOCKS5:
+ 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:
+ /* do nothing here. handled later. */
+ break;
+ default:
+ failf(data, "unknown proxytype option given");
+ result = CURLE_COULDNT_CONNECT;
+ break;
+ }
+
+ if(result) {
+ if(ftpc->count1 == 0 && ftpcode == 229)
+ return ftp_epsv_disable(conn);
+ return result;
+ }
+
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+ /* FIX: this MUST wait for a proper connect first if 'connected' is
+ * FALSE */
+
+ /* BLOCKING */
+ /* We want "seamless" FTP operations through HTTP proxy tunnel */
+
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the member
+ * conn->proto.http; we want FTP through HTTP and we have to change the
+ * member temporarily for connecting to the HTTP proxy. After
+ * Curl_proxyCONNECT we have to set back the member to the original struct
+ * FTP pointer
+ */
+ struct HTTP http_proxy;
+ struct FTP *ftp_save = data->req.protop;
+ memset(&http_proxy, 0, sizeof(http_proxy));
+ data->req.protop = &http_proxy;
+
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, newhost, newport);
+
+ data->req.protop = ftp_save;
+
+ if(result)
+ return result;
+
+ if(conn->tunnel_state[SECONDARYSOCKET] != TUNNEL_COMPLETE) {
+ /* the CONNECT procedure is not complete, the tunnel is not yet up */
+ state(conn, FTP_STOP); /* this phase is completed */
+ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+
+ return result;
+ }
+ }
+
+ conn->bits.tcpconnect[SECONDARYSOCKET] = connected;
+ conn->bits.do_more = TRUE;
+ state(conn, FTP_STOP); /* this phase is completed */
+
+ return result;
+}
+
+static CURLcode ftp_state_port_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ ftpport fcmd = (ftpport)ftpc->count1;
+ CURLcode result = CURLE_OK;
+
+ if(ftpcode != 200) {
+ /* the command failed */
+
+ if(EPRT == fcmd) {
+ infof(data, "disabling EPRT usage\n");
+ conn->bits.ftp_use_eprt = FALSE;
+ }
+ fcmd++;
+
+ if(fcmd == DONE) {
+ failf(data, "Failed to do PORT");
+ result = CURLE_FTP_PORT_FAILED;
+ }
+ else
+ /* try next */
+ result = ftp_state_use_port(conn, fcmd);
+ }
+ else {
+ infof(data, "Connect data stream actively\n");
+ state(conn, FTP_STOP); /* end of DO phase */
+ result = ftp_dophase_done(conn, FALSE);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_mdtm_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data=conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ switch(ftpcode) {
+ case 213:
+ {
+ /* we got a time. Format should be: "YYYYMMDDHHMMSS[.sss]" where the
+ last .sss part is optional and means fractions of a second */
+ int year, month, day, hour, minute, second;
+ char *buf = data->state.buffer;
+ if(6 == sscanf(buf+4, "%04d%02d%02d%02d%02d%02d",
+ &year, &month, &day, &hour, &minute, &second)) {
+ /* we have a time, reformat it */
+ time_t secs=time(NULL);
+ /* using the good old yacc/bison yuck */
+ snprintf(buf, sizeof(conn->data->state.buffer),
+ "%04d%02d%02d %02d:%02d:%02d GMT",
+ year, month, day, hour, minute, second);
+ /* now, convert this into a time() value: */
+ data->info.filetime = (long)curl_getdate(buf, &secs);
+ }
+
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ /* If we asked for a time of the file and we actually got one as well,
+ we "emulate" a HTTP-style header in our output. */
+
+ if(data->set.opt_no_body &&
+ ftpc->file &&
+ data->set.get_filetime &&
+ (data->info.filetime>=0) ) {
+ time_t filetime = (time_t)data->info.filetime;
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+
+ result = Curl_gmtime(filetime, &buffer);
+ if(result)
+ return result;
+
+ /* format: "Tue, 15 Nov 1994 12:45:26" */
+ snprintf(buf, BUFSIZE-1,
+ "Last-Modified: %s, %02d %s %4d %02d:%02d:%02d GMT\r\n",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+ if(result)
+ return result;
+ } /* end of a ridiculous amount of conditionals */
+#endif
+ }
+ break;
+ default:
+ infof(data, "unsupported MDTM reply format\n");
+ break;
+ case 550: /* "No such file or directory" */
+ failf(data, "Given file does not exist");
+ result = CURLE_FTP_COULDNT_RETR_FILE;
+ break;
+ }
+
+ if(data->set.timecondition) {
+ if((data->info.filetime > 0) && (data->set.timevalue > 0)) {
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ if(data->info.filetime <= data->set.timevalue) {
+ infof(data, "The requested document is not new enough\n");
+ ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ data->info.timecond = TRUE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ if(data->info.filetime > data->set.timevalue) {
+ infof(data, "The requested document is not old enough\n");
+ ftp->transfer = FTPTRANSFER_NONE; /* mark to not transfer data */
+ data->info.timecond = TRUE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+ break;
+ } /* switch */
+ }
+ else {
+ infof(data, "Skipping time comparison\n");
+ }
+ }
+
+ if(!result)
+ result = ftp_state_type(conn);
+
+ return result;
+}
+
+static CURLcode ftp_state_type_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data=conn->data;
+
+ if(ftpcode/100 != 2) {
+ /* "sasserftpd" and "(u)r(x)bot ftpd" both responds with 226 after a
+ successful 'TYPE I'. While that is not as RFC959 says, it is still a
+ positive response code and we allow that. */
+ failf(data, "Couldn't set desired mode");
+ return CURLE_FTP_COULDNT_SET_TYPE;
+ }
+ if(ftpcode != 200)
+ infof(data, "Got a %03d response code instead of the assumed 200\n",
+ ftpcode);
+
+ if(instate == FTP_TYPE)
+ result = ftp_state_size(conn);
+ else if(instate == FTP_LIST_TYPE)
+ result = ftp_state_list(conn);
+ else if(instate == FTP_RETR_TYPE)
+ result = ftp_state_retr_prequote(conn);
+ else if(instate == FTP_STOR_TYPE)
+ result = ftp_state_stor_prequote(conn);
+
+ return result;
+}
+
+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->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(data->set.max_filesize && (filesize > data->set.max_filesize)) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ ftp->downloadsize = filesize;
+
+ if(data->state.resume_from) {
+ /* We always (attempt to) get the size of downloads, so it is done before
+ this even when not doing resumes. */
+ if(filesize == -1) {
+ infof(data, "ftp server doesn't support SIZE\n");
+ /* We couldn't get the size and therefore we can't know if there really
+ is a part of the file left to get, although the server will just
+ close the connection when we start the connection so it won't cause
+ us any harm, just not make us exit as nicely. */
+ }
+ else {
+ /* We got a file size report, so we check that there actually is a
+ part of the file left to get, or else we go home. */
+ if(data->state.resume_from< 0) {
+ /* We're supposed to download the last abs(from) bytes */
+ if(filesize < -data->state.resume_from) {
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* convert to size to download */
+ ftp->downloadsize = -data->state.resume_from;
+ /* download from where? */
+ data->state.resume_from = filesize - ftp->downloadsize;
+ }
+ else {
+ if(filesize < data->state.resume_from) {
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* Now store the number of bytes we are expected to download */
+ ftp->downloadsize = filesize-data->state.resume_from;
+ }
+ }
+
+ if(ftp->downloadsize == 0) {
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ infof(data, "File already completely downloaded\n");
+
+ /* Set ->transfer so that we won't get any error in ftp_done()
+ * because we didn't transfer the any file */
+ ftp->transfer = FTPTRANSFER_NONE;
+ state(conn, FTP_STOP);
+ return CURLE_OK;
+ }
+
+ /* Set resume file transfer offset */
+ infof(data, "Instructs server to resume from offset %" FORMAT_OFF_T
+ "\n", data->state.resume_from);
+
+ PPSENDF(&ftpc->pp, "REST %" FORMAT_OFF_T, data->state.resume_from);
+
+ state(conn, FTP_RETR_REST);
+
+ }
+ else {
+ /* no resume */
+ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+ state(conn, FTP_RETR);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_size_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data=conn->data;
+ curl_off_t filesize;
+ char *buf = data->state.buffer;
+
+ /* get the size from the ascii string: */
+ filesize = (ftpcode == 213)?curlx_strtoofft(buf+4, NULL, 0):-1;
+
+ if(instate == FTP_SIZE) {
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ if(-1 != filesize) {
+ snprintf(buf, sizeof(data->state.buffer),
+ "Content-Length: %" FORMAT_OFF_T "\r\n", filesize);
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buf, 0);
+ if(result)
+ return result;
+ }
+#endif
+ Curl_pgrsSetDownloadSize(data, filesize);
+ result = ftp_state_rest(conn);
+ }
+ else if(instate == FTP_RETR_SIZE) {
+ Curl_pgrsSetDownloadSize(data, filesize);
+ result = ftp_state_retr(conn, filesize);
+ }
+ else if(instate == FTP_STOR_SIZE) {
+ data->state.resume_from = filesize;
+ result = ftp_state_ul_setup(conn, TRUE);
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_rest_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ switch(instate) {
+ case FTP_REST:
+ default:
+#ifdef CURL_FTP_HTTPSTYLE_HEAD
+ if(ftpcode == 350) {
+ char buffer[24]= { "Accept-ranges: bytes\r\n" };
+ result = Curl_client_write(conn, CLIENTWRITE_BOTH, buffer, 0);
+ if(result)
+ return result;
+ }
+#endif
+ result = ftp_state_prepare_transfer(conn);
+ break;
+
+ case FTP_RETR_REST:
+ if(ftpcode != 350) {
+ failf(conn->data, "Couldn't use REST");
+ result = CURLE_FTP_COULDNT_USE_REST;
+ }
+ else {
+ PPSENDF(&ftpc->pp, "RETR %s", ftpc->file);
+ state(conn, FTP_RETR);
+ }
+ break;
+ }
+
+ return result;
+}
+
+static CURLcode ftp_state_stor_resp(struct connectdata *conn,
+ int ftpcode, ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ if(ftpcode>=400) {
+ failf(data, "Failed FTP upload: %0d", ftpcode);
+ state(conn, FTP_STOP);
+ /* oops, we never close the sockets! */
+ return CURLE_UPLOAD_FAILED;
+ }
+
+ conn->proto.ftpc.state_saved = instate;
+
+ /* PORT means we are now awaiting the server to connect to us. */
+ 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;
+
+ if(!connected) {
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ infof(data, "Data conn was not available immediately\n");
+ ftpc->wait_data_conn = TRUE;
+ }
+
+ return CURLE_OK;
+ }
+ else
+ return InitiateTransfer(conn);
+}
+
+/* for LIST and RETR responses */
+static CURLcode ftp_state_get_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ char *buf = data->state.buffer;
+
+ if((ftpcode == 150) || (ftpcode == 125)) {
+
+ /*
+ A;
+ 150 Opening BINARY mode data connection for /etc/passwd (2241
+ bytes). (ok, the file is being transferred)
+
+ B:
+ 150 Opening ASCII mode data connection for /bin/ls
+
+ C:
+ 150 ASCII data connection for /bin/ls (137.167.104.91,37445) (0 bytes).
+
+ D:
+ 150 Opening ASCII mode data connection for [file] (0.0.0.0,0) (545 bytes)
+
+ E:
+ 125 Data connection already open; Transfer starting. */
+
+ curl_off_t size=-1; /* default unknown size */
+
+
+ /*
+ * It appears that there are FTP-servers that return size 0 for files when
+ * SIZE is used on the file while being in BINARY mode. To work around
+ * that (stupid) behavior, we attempt to parse the RETR response even if
+ * the SIZE returned size zero.
+ *
+ * Debugging help from Salvatore Sorrentino on February 26, 2003.
+ */
+
+ if((instate != FTP_LIST) &&
+ !data->set.prefer_ascii &&
+ (ftp->downloadsize < 1)) {
+ /*
+ * It seems directory listings either don't show the size or very
+ * often uses size 0 anyway. ASCII transfers may very well turn out
+ * that the transferred amount of data is not the same as this line
+ * tells, why using this number in those cases only confuses us.
+ *
+ * Example D above makes this parsing a little tricky */
+ char *bytes;
+ bytes=strstr(buf, " bytes");
+ if(bytes--) {
+ long in=(long)(bytes-buf);
+ /* this is a hint there is size information in there! ;-) */
+ while(--in) {
+ /* scan for the left parenthesis and break there */
+ if('(' == *bytes)
+ break;
+ /* skip only digits */
+ if(!ISDIGIT(*bytes)) {
+ bytes=NULL;
+ break;
+ }
+ /* one more estep backwards */
+ bytes--;
+ }
+ /* if we have nothing but digits: */
+ if(bytes++) {
+ /* get the number! */
+ size = curlx_strtoofft(bytes, NULL, 0);
+ }
+ }
+ }
+ else if(ftp->downloadsize > -1)
+ size = ftp->downloadsize;
+
+ if(size > data->req.maxdownload && data->req.maxdownload > 0)
+ size = data->req.size = data->req.maxdownload;
+ else if((instate != FTP_LIST) && (data->set.prefer_ascii))
+ size = -1; /* kludge for servers that understate ASCII mode file size */
+
+ infof(data, "Maxdownload = %" FORMAT_OFF_T "\n", data->req.maxdownload);
+
+ if(instate != FTP_LIST)
+ infof(data, "Getting file with size: %" FORMAT_OFF_T "\n", size);
+
+ /* FTP download: */
+ conn->proto.ftpc.state_saved = instate;
+ conn->proto.ftpc.retr_size_saved = size;
+
+ if(data->set.ftp_use_port) {
+ bool connected;
+
+ result = AllowServerConnect(conn, &connected);
+ if(result)
+ return result;
+
+ if(!connected) {
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ infof(data, "Data conn was not available immediately\n");
+ state(conn, FTP_STOP);
+ ftpc->wait_data_conn = TRUE;
+ }
+ }
+ else
+ return InitiateTransfer(conn);
+ }
+ else {
+ if((instate == FTP_LIST) && (ftpcode == 450)) {
+ /* simply no matching files in the dir listing */
+ ftp->transfer = FTPTRANSFER_NONE; /* don't download anything */
+ state(conn, FTP_STOP); /* this phase is over */
+ }
+ else {
+ failf(data, "RETR response: %03d", ftpcode);
+ return instate == FTP_RETR && ftpcode == 550?
+ CURLE_REMOTE_FILE_NOT_FOUND:
+ CURLE_FTP_COULDNT_RETR_FILE;
+ }
+ }
+
+ return result;
+}
+
+/* after USER, PASS and ACCT */
+static CURLcode ftp_state_loggedin(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ if(conn->ssl[FIRSTSOCKET].use) {
+ /* PBSZ = PROTECTION BUFFER SIZE.
+
+ The 'draft-murray-auth-ftp-ssl' (draft 12, page 7) says:
+
+ Specifically, the PROT command MUST be preceded by a PBSZ
+ command and a PBSZ command MUST be preceded by a successful
+ security data exchange (the TLS negotiation in this case)
+
+ ... (and on page 8):
+
+ Thus the PBSZ command must still be issued, but must have a
+ parameter of '0' to indicate that no buffering is taking place
+ and the data connection should not be encapsulated.
+ */
+ PPSENDF(&conn->proto.ftpc.pp, "PBSZ %d", 0);
+ state(conn, FTP_PBSZ);
+ }
+ else {
+ result = ftp_state_pwd(conn);
+ }
+ return result;
+}
+
+/* for USER and PASS responses */
+static CURLcode ftp_state_user_resp(struct connectdata *conn,
+ int ftpcode,
+ ftpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ (void)instate; /* no use for this yet */
+
+ /* some need password anyway, and others just return 2xx ignored */
+ if((ftpcode == 331) && (ftpc->state == FTP_USER)) {
+ /* 331 Password required for ...
+ (the server requires to send the user's password too) */
+ PPSENDF(&ftpc->pp, "PASS %s", ftp->passwd?ftp->passwd:"");
+ state(conn, FTP_PASS);
+ }
+ else if(ftpcode/100 == 2) {
+ /* 230 User ... logged in.
+ (the user logged in with or without password) */
+ result = ftp_state_loggedin(conn);
+ }
+ else if(ftpcode == 332) {
+ if(data->set.str[STRING_FTP_ACCOUNT]) {
+ PPSENDF(&ftpc->pp, "ACCT %s", data->set.str[STRING_FTP_ACCOUNT]);
+ state(conn, FTP_ACCT);
+ }
+ else {
+ failf(data, "ACCT requested but none available");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+ else {
+ /* All other response codes, like:
+
+ 530 User ... access denied
+ (the server denies to log the specified user) */
+
+ if(conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER] &&
+ !conn->data->state.ftp_trying_alternative) {
+ /* Ok, USER failed. Let's try the supplied command. */
+ PPSENDF(&conn->proto.ftpc.pp, "%s",
+ conn->data->set.str[STRING_FTP_ALTERNATIVE_TO_USER]);
+ conn->data->state.ftp_trying_alternative = TRUE;
+ state(conn, FTP_USER);
+ result = CURLE_OK;
+ }
+ else {
+ failf(data, "Access denied: %03d", ftpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+ return result;
+}
+
+/* for ACCT response */
+static CURLcode ftp_state_acct_resp(struct connectdata *conn,
+ int ftpcode)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ if(ftpcode != 230) {
+ failf(data, "ACCT rejected by server: %03d", ftpcode);
+ result = CURLE_FTP_WEIRD_PASS_REPLY; /* FIX */
+ }
+ else
+ result = ftp_state_loggedin(conn);
+
+ return result;
+}
+
+
+static CURLcode ftp_statemach_act(struct connectdata *conn)
+{
+ CURLcode result;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ struct SessionHandle *data=conn->data;
+ int ftpcode;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ static const char ftpauth[][4] = { "SSL", "TLS" };
+ size_t nread = 0;
+
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ result = ftp_readresp(sock, pp, &ftpcode, &nread);
+ if(result)
+ return result;
+
+ if(ftpcode) {
+ /* we have now received a full FTP server response */
+ switch(ftpc->state) {
+ case FTP_WAIT220:
+ 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. */
+#ifdef HAVE_GSSAPI
+ if(data->set.krb) {
+ /* If not anonymous login, try a secure login. Note that this
+ procedure is still BLOCKING. */
+
+ Curl_sec_request_prot(conn, "private");
+ /* We set private first as default, in case the line below fails to
+ set a valid level */
+ Curl_sec_request_prot(conn, data->set.str[STRING_KRB_LEVEL]);
+
+ if(Curl_sec_login(conn) != CURLE_OK)
+ infof(data, "Logging in with password in cleartext!\n");
+ else
+ infof(data, "Authentication successful\n");
+ }
+#endif
+
+ if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but FTPS is
+ requested. Try a FTPS connection now */
+
+ ftpc->count3=0;
+ switch(data->set.ftpsslauth) {
+ case CURLFTPAUTH_DEFAULT:
+ case CURLFTPAUTH_SSL:
+ ftpc->count2 = 1; /* add one to get next */
+ ftpc->count1 = 0;
+ break;
+ case CURLFTPAUTH_TLS:
+ ftpc->count2 = -1; /* subtract one to get next */
+ ftpc->count1 = 1;
+ break;
+ default:
+ failf(data, "unsupported parameter to CURLOPT_FTPSSLAUTH: %d",
+ (int)data->set.ftpsslauth);
+ return CURLE_UNKNOWN_OPTION; /* we don't know what to do */
+ }
+ PPSENDF(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+ state(conn, FTP_AUTH);
+ }
+ else {
+ result = ftp_state_user(conn);
+ if(result)
+ return result;
+ }
+
+ break;
+
+ case FTP_AUTH:
+ /* we have gotten the response to a previous AUTH command */
+
+ /* RFC2228 (page 5) says:
+ *
+ * If the server is willing to accept the named security mechanism,
+ * and does not require any security data, it must respond with
+ * reply code 234/334.
+ */
+
+ if((ftpcode == 234) || (ftpcode == 334)) {
+ /* Curl_ssl_connect is BLOCKING */
+ result = Curl_ssl_connect(conn, FIRSTSOCKET);
+ if(CURLE_OK == result) {
+ conn->ssl[SECONDARYSOCKET].use = FALSE; /* clear-text data */
+ result = ftp_state_user(conn);
+ }
+ }
+ else if(ftpc->count3 < 1) {
+ ftpc->count3++;
+ ftpc->count1 += ftpc->count2; /* get next attempt */
+ result = Curl_pp_sendf(&ftpc->pp, "AUTH %s", ftpauth[ftpc->count1]);
+ /* remain in this same state */
+ }
+ else {
+ if(data->set.use_ssl > CURLUSESSL_TRY)
+ /* we failed and CURLUSESSL_CONTROL or CURLUSESSL_ALL is set */
+ result = CURLE_USE_SSL_FAILED;
+ else
+ /* ignore the failure and continue */
+ result = ftp_state_user(conn);
+ }
+
+ if(result)
+ return result;
+ break;
+
+ case FTP_USER:
+ case FTP_PASS:
+ result = ftp_state_user_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_ACCT:
+ result = ftp_state_acct_resp(conn, ftpcode);
+ break;
+
+ case FTP_PBSZ:
+ PPSENDF(&ftpc->pp, "PROT %c",
+ data->set.use_ssl == CURLUSESSL_CONTROL ? 'C' : 'P');
+ state(conn, FTP_PROT);
+
+ break;
+
+ case FTP_PROT:
+ if(ftpcode/100 == 2)
+ /* We have enabled SSL for the data connection! */
+ conn->ssl[SECONDARYSOCKET].use =
+ (data->set.use_ssl != CURLUSESSL_CONTROL) ? TRUE : FALSE;
+ /* FTP servers typically responds with 500 if they decide to reject
+ our 'P' request */
+ else if(data->set.use_ssl > CURLUSESSL_CONTROL)
+ /* we failed and bails out */
+ return CURLE_USE_SSL_FAILED;
+
+ if(data->set.ftp_ccc) {
+ /* CCC - Clear Command Channel
+ */
+ PPSENDF(&ftpc->pp, "%s", "CCC");
+ state(conn, FTP_CCC);
+ }
+ else {
+ result = ftp_state_pwd(conn);
+ if(result)
+ return result;
+ }
+ break;
+
+ case FTP_CCC:
+ if(ftpcode < 500) {
+ /* First shut down the SSL layer (note: this call will block) */
+ result = Curl_ssl_shutdown(conn, FIRSTSOCKET);
+
+ if(result) {
+ failf(conn->data, "Failed to clear the command channel (CCC)");
+ return result;
+ }
+ }
+
+ /* Then continue as normal */
+ result = ftp_state_pwd(conn);
+ if(result)
+ return result;
+ break;
+
+ case FTP_PWD:
+ if(ftpcode == 257) {
+ char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ char *dir;
+ char *store;
+
+ dir = malloc(nread + 1);
+ if(!dir)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Reply format is like
+ 257<space>[rubbish]"<directory-name>"<space><commentary> and the
+ RFC959 says
+
+ The directory name can contain any character; embedded
+ double-quotes should be escaped by double-quotes (the
+ "quote-doubling" convention).
+ */
+
+ /* scan for the first double-quote for non-standard responses */
+ while(ptr < &data->state.buffer[sizeof(data->state.buffer)]
+ && *ptr != '\n' && *ptr != '\0' && *ptr != '"')
+ ptr++;
+
+ if('\"' == *ptr) {
+ /* it started good */
+ ptr++;
+ for(store = dir; *ptr;) {
+ if('\"' == *ptr) {
+ if('\"' == ptr[1]) {
+ /* "quote-doubling" */
+ *store = ptr[1];
+ ptr++;
+ }
+ else {
+ /* end of path */
+ *store = '\0'; /* zero terminate */
+ break; /* get out of this loop */
+ }
+ }
+ else
+ *store = *ptr;
+ store++;
+ ptr++;
+ }
+
+ /* If the path name does not look like an absolute path (i.e.: it
+ does not start with a '/'), we probably need some server-dependent
+ adjustments. For example, this is the case when connecting to
+ an OS400 FTP server: this server supports two name syntaxes,
+ the default one being incompatible with standard pathes. In
+ addition, this server switches automatically to the regular path
+ syntax when one is encountered in a command: this results in
+ having an entrypath in the wrong syntax when later used in CWD.
+ The method used here is to check the server OS: we do it only
+ if the path name looks strange to minimize overhead on other
+ systems. */
+
+ if(!ftpc->server_os && dir[0] != '/') {
+
+ result = Curl_pp_sendf(&ftpc->pp, "%s", "SYST");
+ if(result != CURLE_OK) {
+ free(dir);
+ return result;
+ }
+ Curl_safefree(ftpc->entrypath);
+ ftpc->entrypath = dir; /* remember this */
+ infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ /* also save it where getinfo can access it: */
+ data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+ state(conn, FTP_SYST);
+ break;
+ }
+
+ Curl_safefree(ftpc->entrypath);
+ ftpc->entrypath = dir; /* remember this */
+ infof(data, "Entry path is '%s'\n", ftpc->entrypath);
+ /* also save it where getinfo can access it: */
+ data->state.most_recent_ftp_entrypath = ftpc->entrypath;
+ }
+ else {
+ /* couldn't get the path */
+ free(dir);
+ infof(data, "Failed to figure out path\n");
+ }
+ }
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_SYST:
+ if(ftpcode == 215) {
+ char *ptr=&data->state.buffer[4]; /* start on the first letter */
+ char *os;
+ char *store;
+
+ os = malloc(nread + 1);
+ if(!os)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Reply format is like
+ 215<space><OS-name><space><commentary>
+ */
+ while(*ptr == ' ')
+ ptr++;
+ for(store = os; *ptr && *ptr != ' ';)
+ *store++ = *ptr++;
+ *store = '\0'; /* zero terminate */
+
+ /* Check for special servers here. */
+
+ if(strequal(os, "OS/400")) {
+ /* Force OS400 name format 1. */
+ result = Curl_pp_sendf(&ftpc->pp, "%s", "SITE NAMEFMT 1");
+ if(result != CURLE_OK) {
+ free(os);
+ return result;
+ }
+ /* remember target server OS */
+ Curl_safefree(ftpc->server_os);
+ ftpc->server_os = os;
+ state(conn, FTP_NAMEFMT);
+ break;
+ }
+ else {
+ /* Nothing special for the target server. */
+ /* remember target server OS */
+ Curl_safefree(ftpc->server_os);
+ ftpc->server_os = os;
+ }
+ }
+ else {
+ /* Cannot identify server OS. Continue anyway and cross fingers. */
+ }
+
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_NAMEFMT:
+ if(ftpcode == 250) {
+ /* Name format change successful: reload initial path. */
+ ftp_state_pwd(conn);
+ break;
+ }
+
+ state(conn, FTP_STOP); /* we are done with the CONNECT phase! */
+ DEBUGF(infof(data, "protocol connect phase DONE\n"));
+ break;
+
+ case FTP_QUOTE:
+ case FTP_POSTQUOTE:
+ case FTP_RETR_PREQUOTE:
+ case FTP_STOR_PREQUOTE:
+ if((ftpcode >= 400) && !ftpc->count2) {
+ /* failure response code, and not allowed to fail */
+ failf(conn->data, "QUOT command failed with %03d", ftpcode);
+ return CURLE_QUOTE_ERROR;
+ }
+ result = ftp_state_quote(conn, FALSE, ftpc->state);
+ if(result)
+ return result;
+
+ break;
+
+ case FTP_CWD:
+ if(ftpcode/100 != 2) {
+ /* failure to CWD there */
+ if(conn->data->set.ftp_create_missing_dirs &&
+ ftpc->count1 && !ftpc->count2) {
+ /* try making it */
+ ftpc->count2++; /* counter to prevent CWD-MKD loops */
+ PPSENDF(&ftpc->pp, "MKD %s", ftpc->dirs[ftpc->count1 - 1]);
+ state(conn, FTP_MKD);
+ }
+ else {
+ /* return failure */
+ failf(data, "Server denied you to change to the given directory");
+ ftpc->cwdfail = TRUE; /* don't remember this path as we failed
+ to enter it */
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ }
+ else {
+ /* success */
+ ftpc->count2=0;
+ if(++ftpc->count1 <= ftpc->dirdepth) {
+ /* send next CWD */
+ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+ }
+ else {
+ result = ftp_state_mdtm(conn);
+ if(result)
+ return result;
+ }
+ }
+ break;
+
+ case FTP_MKD:
+ if((ftpcode/100 != 2) && !ftpc->count3--) {
+ /* failure to MKD the dir */
+ failf(data, "Failed to MKD dir: %03d", ftpcode);
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+ state(conn, FTP_CWD);
+ /* send CWD */
+ PPSENDF(&ftpc->pp, "CWD %s", ftpc->dirs[ftpc->count1 - 1]);
+ break;
+
+ case FTP_MDTM:
+ result = ftp_state_mdtm_resp(conn, ftpcode);
+ break;
+
+ case FTP_TYPE:
+ case FTP_LIST_TYPE:
+ case FTP_RETR_TYPE:
+ case FTP_STOR_TYPE:
+ result = ftp_state_type_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_SIZE:
+ case FTP_RETR_SIZE:
+ case FTP_STOR_SIZE:
+ result = ftp_state_size_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_REST:
+ case FTP_RETR_REST:
+ result = ftp_state_rest_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_PRET:
+ if(ftpcode != 200) {
+ /* there only is this one standard OK return code. */
+ failf(data, "PRET command not accepted: %03d", ftpcode);
+ return CURLE_FTP_PRET_FAILED;
+ }
+ result = ftp_state_use_pasv(conn);
+ break;
+
+ case FTP_PASV:
+ result = ftp_state_pasv_resp(conn, ftpcode);
+ break;
+
+ case FTP_PORT:
+ result = ftp_state_port_resp(conn, ftpcode);
+ break;
+
+ case FTP_LIST:
+ case FTP_RETR:
+ result = ftp_state_get_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_STOR:
+ result = ftp_state_stor_resp(conn, ftpcode, ftpc->state);
+ break;
+
+ case FTP_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, FTP_STOP);
+ break;
+ }
+ } /* if(ftpcode) */
+
+ return result;
+}
+
+
+/* called repeatedly until done from multi.c */
+static CURLcode ftp_multi_statemach(struct connectdata *conn,
+ bool *done)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result = Curl_pp_statemach(&ftpc->pp, FALSE);
+
+ /* Check for the state outside of the Curl_socket_ready() return code checks
+ since at times we are in fact already in this state when this function
+ gets called. */
+ *done = (ftpc->state == FTP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode ftp_block_statemach(struct connectdata *conn)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ CURLcode result = CURLE_OK;
+
+ while(ftpc->state != FTP_STOP) {
+ result = Curl_pp_statemach(pp, TRUE);
+ if(result)
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * 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 if not.
+ *
+ */
+static CURLcode ftp_connect(struct connectdata *conn,
+ bool *done) /* see description above */
+{
+ CURLcode result;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections on ftp */
+ conn->bits.close = FALSE;
+
+ pp->response_time = RESP_TIMEOUT; /* set default response time-out */
+ pp->statemach_act = ftp_statemach_act;
+ pp->endofresp = ftp_endofresp;
+ pp->conn = conn;
+
+ if(conn->handler->flags & PROTOPT_SSL) {
+ /* BLOCKING */
+ result = Curl_ssl_connect(conn, FIRSTSOCKET);
+ if(result)
+ return result;
+ }
+
+ Curl_pp_init(pp); /* init the generic pingpong data */
+
+ /* When we connect, we start in the state where we await the 220
+ response */
+ state(conn, FTP_WAIT220);
+
+ result = ftp_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode ftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ struct SessionHandle *data = conn->data;
+ struct FTP *ftp = data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+ ssize_t nread;
+ int ftpcode;
+ CURLcode result = CURLE_OK;
+ bool was_ctl_valid = ftpc->ctl_valid;
+ char *path;
+ const char *path_to_use = data->state.path;
+
+ if(!ftp)
+ /* When the easy handle is removed from the multi while libcurl is still
+ * trying to resolve the host name, it seems that the ftp struct is not
+ * yet initialized, but the removal action calls Curl_done() which calls
+ * this function. So we simply return success if no ftp pointer is set.
+ */
+ return CURLE_OK;
+
+ switch(status) {
+ case CURLE_BAD_DOWNLOAD_RESUME:
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ case CURLE_FTP_PORT_FAILED:
+ case CURLE_FTP_ACCEPT_FAILED:
+ case CURLE_FTP_ACCEPT_TIMEOUT:
+ case CURLE_FTP_COULDNT_SET_TYPE:
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ case CURLE_PARTIAL_FILE:
+ case CURLE_UPLOAD_FAILED:
+ case CURLE_REMOTE_ACCESS_DENIED:
+ case CURLE_FILESIZE_EXCEEDED:
+ case CURLE_REMOTE_FILE_NOT_FOUND:
+ case CURLE_WRITE_ERROR:
+ /* the connection stays alive fine even though this happened */
+ /* fall-through */
+ case CURLE_OK: /* doesn't affect the control connection's status */
+ if(!premature) {
+ ftpc->ctl_valid = was_ctl_valid;
+ break;
+ }
+ /* until we cope better with prematurely ended requests, let them
+ * fallback as if in complete failure */
+ default: /* by default, an error means the control connection is
+ wedged and should not be used anymore */
+ ftpc->ctl_valid = FALSE;
+ ftpc->cwdfail = TRUE; /* set this TRUE to prevent us to remember the
+ current path, as this connection is going */
+ conn->bits.close = TRUE; /* marked for closure */
+ result = status; /* use the already set error code */
+ break;
+ }
+
+ /* now store a copy of the directory we are in */
+ if(ftpc->prevpath)
+ free(ftpc->prevpath);
+
+ if(data->set.wildcardmatch) {
+ if(data->set.chunk_end && ftpc->file) {
+ data->set.chunk_end(data->wildcard.customptr);
+ }
+ ftpc->known_filesize = -1;
+ }
+
+ /* get the "raw" path */
+ path = curl_easy_unescape(data, path_to_use, 0, NULL);
+ if(!path) {
+ /* out of memory, but we can limp along anyway (and should try to
+ * since we may already be in the out of memory cleanup path) */
+ if(!result)
+ result = CURLE_OUT_OF_MEMORY;
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ conn->bits.close = TRUE; /* mark for connection closure */
+ ftpc->prevpath = NULL; /* no path remembering */
+ }
+ else {
+ size_t flen = ftpc->file?strlen(ftpc->file):0; /* file is "raw" already */
+ size_t dlen = strlen(path)-flen;
+ if(!ftpc->cwdfail) {
+ if(dlen && (data->set.ftp_filemethod != FTPFILE_NOCWD)) {
+ ftpc->prevpath = path;
+ if(flen)
+ /* if 'path' is not the whole string */
+ ftpc->prevpath[dlen]=0; /* terminate */
+ }
+ else {
+ /* we never changed dir */
+ ftpc->prevpath=strdup("");
+ free(path);
+ }
+ if(ftpc->prevpath)
+ infof(data, "Remembering we are in dir \"%s\"\n", ftpc->prevpath);
+ }
+ else {
+ ftpc->prevpath = NULL; /* no path */
+ free(path);
+ }
+ }
+ /* free the dir tree and file parts */
+ freedirs(ftpc);
+
+ /* shut down the socket to inform the server we're done */
+
+#ifdef _WIN32_WCE
+ shutdown(conn->sock[SECONDARYSOCKET],2); /* SD_BOTH */
+#endif
+
+ if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+ if(!result && ftpc->dont_check && data->req.maxdownload > 0) {
+ /* partial download completed */
+ result = Curl_pp_sendf(pp, "%s", "ABOR");
+ if(result) {
+ failf(data, "Failure sending ABOR command: %s",
+ curl_easy_strerror(result));
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ conn->bits.close = TRUE; /* mark for connection closure */
+ }
+ }
+
+ if(conn->ssl[SECONDARYSOCKET].use) {
+ /* The secondary socket is using SSL so we must close down that part
+ first before we close the socket for real */
+ Curl_ssl_close(conn, SECONDARYSOCKET);
+
+ /* Note that we keep "use" set to TRUE since that (next) connection is
+ still requested to use SSL */
+ }
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET]) {
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+ conn->bits.tcpconnect[SECONDARYSOCKET] = FALSE;
+ }
+ }
+
+ if(!result && (ftp->transfer == FTPTRANSFER_BODY) && ftpc->ctl_valid &&
+ pp->pending_resp && !premature) {
+ /*
+ * Let's see what the server says about the transfer we just performed,
+ * but lower the timeout as sometimes this connection has died while the
+ * data has been transferred. This happens when doing through NATs etc that
+ * abandon old silent connections.
+ */
+ long old_time = pp->response_time;
+
+ pp->response_time = 60*1000; /* give it only a minute for now */
+ pp->response = Curl_tvnow(); /* timeout relative now */
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+
+ pp->response_time = old_time; /* set this back to previous value */
+
+ if(!nread && (CURLE_OPERATION_TIMEDOUT == result)) {
+ failf(data, "control connection looks dead");
+ ftpc->ctl_valid = FALSE; /* mark control connection as bad */
+ conn->bits.close = TRUE; /* mark for closure */
+ }
+
+ if(result)
+ return result;
+
+ if(ftpc->dont_check && data->req.maxdownload > 0) {
+ /* we have just sent ABOR and there is no reliable way to check if it was
+ * successful or not; we have to close the connection now */
+ infof(data, "partial download completed, closing connection\n");
+ conn->bits.close = TRUE; /* mark for closure */
+ return result;
+ }
+
+ if(!ftpc->dont_check) {
+ /* 226 Transfer complete, 250 Requested file action okay, completed. */
+ if((ftpcode != 226) && (ftpcode != 250)) {
+ failf(data, "server did not report OK, got %d", ftpcode);
+ result = CURLE_PARTIAL_FILE;
+ }
+ }
+ }
+
+ if(result || premature)
+ /* the response code from the transfer showed an error already so no
+ use checking further */
+ ;
+ else if(data->set.upload) {
+ if((-1 != data->set.infilesize) &&
+ (data->set.infilesize != *ftp->bytecountp) &&
+ !data->set.crlf &&
+ (ftp->transfer == FTPTRANSFER_BODY)) {
+ failf(data, "Uploaded unaligned file size (%" FORMAT_OFF_T
+ " out of %" FORMAT_OFF_T " bytes)",
+ *ftp->bytecountp, data->set.infilesize);
+ result = CURLE_PARTIAL_FILE;
+ }
+ }
+ else {
+ if((-1 != data->req.size) &&
+ (data->req.size != *ftp->bytecountp) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs, so
+ * we'll check to see if the discrepancy can be explained by the number
+ * of CRLFs we've changed to LFs.
+ */
+ ((data->req.size + data->state.crlf_conversions) !=
+ *ftp->bytecountp) &&
+#endif /* CURL_DO_LINEEND_CONV */
+ (data->req.maxdownload != *ftp->bytecountp)) {
+ failf(data, "Received only partial file: %" FORMAT_OFF_T " bytes",
+ *ftp->bytecountp);
+ result = CURLE_PARTIAL_FILE;
+ }
+ else if(!ftpc->dont_check &&
+ !*ftp->bytecountp &&
+ (data->req.size>0)) {
+ failf(data, "No data was received!");
+ result = CURLE_FTP_COULDNT_RETR_FILE;
+ }
+ }
+
+ /* clear these for next connection */
+ ftp->transfer = FTPTRANSFER_BODY;
+ ftpc->dont_check = FALSE;
+
+ /* Send any post-transfer QUOTE strings? */
+ if(!status && !result && !premature && data->set.postquote)
+ result = ftp_sendquote(conn, data->set.postquote);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_sendquote()
+ *
+ * Where a 'quote' means a list of custom commands to send to the server.
+ * The quote list is passed as an argument.
+ *
+ * BLOCKING
+ */
+
+static
+CURLcode ftp_sendquote(struct connectdata *conn, struct curl_slist *quote)
+{
+ struct curl_slist *item;
+ ssize_t nread;
+ int ftpcode;
+ CURLcode result;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ item = quote;
+ while(item) {
+ if(item->data) {
+ char *cmd = item->data;
+ bool acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal FTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ acceptfail = TRUE;
+ }
+
+ PPSENDF(&conn->proto.ftpc.pp, "%s", cmd);
+
+ pp->response = Curl_tvnow(); /* timeout relative now */
+
+ result = Curl_GetFTPResponse(&nread, conn, &ftpcode);
+ if(result)
+ return result;
+
+ if(!acceptfail && (ftpcode >= 400)) {
+ failf(conn->data, "QUOT string not accepted: %s", cmd);
+ return CURLE_QUOTE_ERROR;
+ }
+ }
+
+ item = item->next;
+ }
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_need_type()
+ *
+ * Returns TRUE if we in the current situation should send TYPE
+ */
+static int ftp_need_type(struct connectdata *conn,
+ bool ascii_wanted)
+{
+ return conn->proto.ftpc.transfertype != (ascii_wanted?'A':'I');
+}
+
+/***********************************************************************
+ *
+ * ftp_nb_type()
+ *
+ * Set TYPE. We only deal with ASCII or BINARY so this function
+ * sets one of them.
+ * If the transfer type is not sent, simulate on OK response in newstate
+ */
+static CURLcode ftp_nb_type(struct connectdata *conn,
+ bool ascii, ftpstate newstate)
+{
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ CURLcode result;
+ char want = (char)(ascii?'A':'I');
+
+ if(ftpc->transfertype == want) {
+ state(conn, newstate);
+ return ftp_state_type_resp(conn, 200, newstate);
+ }
+
+ PPSENDF(&ftpc->pp, "TYPE %c", want);
+ state(conn, newstate);
+
+ /* keep track of our current transfer type */
+ ftpc->transfertype = want;
+ return CURLE_OK;
+}
+
+/***************************************************************************
+ *
+ * ftp_pasv_verbose()
+ *
+ * This function only outputs some informationals about this second connection
+ * when we've issued a PASV command before and thus we have connected to a
+ * possibly new IP address.
+ *
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void
+ftp_pasv_verbose(struct connectdata *conn,
+ Curl_addrinfo *ai,
+ char *newhost, /* ascii version */
+ int port)
+{
+ char buf[256];
+ Curl_printable_address(ai, buf, sizeof(buf));
+ infof(conn->data, "Connecting to %s (%s) port %d\n", newhost, buf, port);
+}
+#endif
+
+/*
+ Check if this is a range download, and if so, set the internal variables
+ properly.
+ */
+
+static CURLcode ftp_range(struct connectdata *conn)
+{
+ curl_off_t from, to;
+ char *ptr;
+ char *ptr2;
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(data->state.use_range && data->state.range) {
+ from=curlx_strtoofft(data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if(ptr == ptr2) {
+ /* we didn't get any digit */
+ to=-1;
+ }
+ if((-1 == to) && (from>=0)) {
+ /* X - */
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE %" FORMAT_OFF_T " to end of file\n",
+ from));
+ }
+ else if(from < 0) {
+ /* -Y */
+ data->req.maxdownload = -from;
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE the last %" FORMAT_OFF_T " bytes\n",
+ -from));
+ }
+ else {
+ /* X-Y */
+ data->req.maxdownload = (to-from)+1; /* include last byte */
+ data->state.resume_from = from;
+ DEBUGF(infof(conn->data, "FTP RANGE from %" FORMAT_OFF_T
+ " getting %" FORMAT_OFF_T " bytes\n",
+ from, data->req.maxdownload));
+ }
+ DEBUGF(infof(conn->data, "range-download from %" FORMAT_OFF_T
+ " to %" FORMAT_OFF_T ", totally %" FORMAT_OFF_T " bytes\n",
+ from, to, data->req.maxdownload));
+ ftpc->dont_check = TRUE; /* dont check for successful transfer */
+ }
+ else
+ data->req.maxdownload = -1;
+ return CURLE_OK;
+}
+
+
+/*
+ * ftp_do_more()
+ *
+ * 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, 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->req.protop;
+
+ /* if the second connection isn't done yet, wait for it */
+ if(!conn->bits.tcpconnect[SECONDARYSOCKET]) {
+ if(conn->tunnel_state[SECONDARYSOCKET] == TUNNEL_CONNECT) {
+ /* As we're in TUNNEL_CONNECT state now, we know the proxy name and port
+ aren't used so we blank their arguments. TODO: make this nicer */
+ result = Curl_proxyCONNECT(conn, SECONDARYSOCKET, NULL, 0);
+
+ return result;
+ }
+
+ result = Curl_is_connected(conn, SECONDARYSOCKET, &connected);
+
+ /* Ready to do more? */
+ if(connected) {
+ DEBUGF(infof(data, "DO-MORE connected phase starts\n"));
+ }
+ 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);
+
+ *completep = (int)complete;
+
+ /* if we got an error or if we don't wait for a data connection return
+ immediately */
+ if(result || (ftpc->wait_data_conn != TRUE))
+ return result;
+
+ if(ftpc->wait_data_conn)
+ /* 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 */
+ *completep = 0;
+ }
+
+ if(ftp->transfer <= FTPTRANSFER_INFO) {
+ /* a transfer is about to take place, or if not a file name was given
+ so we'll do a SIZE on it later and then we need the right TYPE first */
+
+ if(ftpc->wait_data_conn == TRUE) {
+ bool serv_conned;
+
+ result = ReceivedServerConnect(conn, &serv_conned);
+ if(result)
+ return result; /* Failed to accept data connection */
+
+ if(serv_conned) {
+ /* It looks data connection is established */
+ result = AcceptServerConnect(conn);
+ ftpc->wait_data_conn = FALSE;
+ if(!result)
+ result = InitiateTransfer(conn);
+
+ if(result)
+ return result;
+
+ *completep = 1; /* this state is now complete when the server has
+ connected back to us */
+ }
+ }
+ else if(data->set.upload) {
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_STOR_TYPE);
+ if(result)
+ return result;
+
+ result = ftp_multi_statemach(conn, &complete);
+ *completep = (int)complete;
+ }
+ else {
+ /* download */
+ ftp->downloadsize = -1; /* unknown as of yet */
+
+ result = ftp_range(conn);
+ if(result)
+ ;
+ else if(data->set.ftp_list_only || !ftpc->file) {
+ /* The specified path ends with a slash, and therefore we think this
+ is a directory that is requested, use LIST. But before that we
+ need to set ASCII transfer mode. */
+
+ /* But only if a body transfer was requested. */
+ if(ftp->transfer == FTPTRANSFER_BODY) {
+ result = ftp_nb_type(conn, TRUE, FTP_LIST_TYPE);
+ if(result)
+ return result;
+ }
+ /* otherwise just fall through */
+ }
+ else {
+ result = ftp_nb_type(conn, data->set.prefer_ascii, FTP_RETR_TYPE);
+ if(result)
+ return result;
+ }
+
+ result = ftp_multi_statemach(conn, &complete);
+ *completep = (int)complete;
+ }
+ return result;
+ }
+
+ if((result == CURLE_OK) && (ftp->transfer != FTPTRANSFER_BODY))
+ /* no data to transfer. FIX: it feels like a kludge to have this here
+ too! */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ if(!ftpc->wait_data_conn) {
+ /* no waiting for the data connection so this is now complete */
+ *completep = 1;
+ DEBUGF(infof(data, "DO-MORE phase ends with %d\n", (int)result));
+ }
+
+ return result;
+}
+
+
+
+/***********************************************************************
+ *
+ * ftp_perform()
+ *
+ * This is the actual DO function for FTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode ftp_perform(struct connectdata *conn,
+ bool *connected, /* connect status after PASV / PORT */
+ bool *dophase_done)
+{
+ /* this is FTP and no proxy */
+ CURLcode result=CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* requested no body means no transfer... */
+ struct FTP *ftp = conn->data->req.protop;
+ ftp->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ result = ftp_state_quote(conn, TRUE, FTP_QUOTE);
+ if(result)
+ return result;
+
+ /* run the state-machine */
+ result = ftp_multi_statemach(conn, dophase_done);
+
+ *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"));
+
+ return result;
+}
+
+static void wc_data_dtor(void *ptr)
+{
+ struct ftp_wc_tmpdata *tmp = ptr;
+ if(tmp)
+ Curl_ftp_parselist_data_free(&tmp->parser);
+ Curl_safefree(tmp);
+}
+
+static CURLcode init_wc_data(struct connectdata *conn)
+{
+ char *last_slash;
+ char *path = conn->data->state.path;
+ struct WildcardData *wildcard = &(conn->data->wildcard);
+ CURLcode ret = CURLE_OK;
+ struct ftp_wc_tmpdata *ftp_tmp;
+
+ last_slash = strrchr(conn->data->state.path, '/');
+ if(last_slash) {
+ last_slash++;
+ if(last_slash[0] == '\0') {
+ wildcard->state = CURLWC_CLEAN;
+ ret = ftp_parse_url_path(conn);
+ return ret;
+ }
+ else {
+ wildcard->pattern = strdup(last_slash);
+ if(!wildcard->pattern)
+ return CURLE_OUT_OF_MEMORY;
+ last_slash[0] = '\0'; /* cut file from path */
+ }
+ }
+ else { /* there is only 'wildcard pattern' or nothing */
+ if(path[0]) {
+ wildcard->pattern = strdup(path);
+ if(!wildcard->pattern)
+ return CURLE_OUT_OF_MEMORY;
+ path[0] = '\0';
+ }
+ else { /* only list */
+ wildcard->state = CURLWC_CLEAN;
+ ret = ftp_parse_url_path(conn);
+ return ret;
+ }
+ }
+
+ /* program continues only if URL is not ending with slash, allocate needed
+ resources for wildcard transfer */
+
+ /* allocate ftp protocol specific temporary wildcard data */
+ ftp_tmp = calloc(1, sizeof(struct ftp_wc_tmpdata));
+ if(!ftp_tmp) {
+ Curl_safefree(wildcard->pattern);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* INITIALIZE parselist structure */
+ ftp_tmp->parser = Curl_ftp_parselist_data_alloc();
+ if(!ftp_tmp->parser) {
+ Curl_safefree(wildcard->pattern);
+ Curl_safefree(ftp_tmp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ wildcard->tmp = ftp_tmp; /* put it to the WildcardData tmp pointer */
+ wildcard->tmp_dtor = wc_data_dtor;
+
+ /* wildcard does not support NOCWD option (assert it?) */
+ if(conn->data->set.ftp_filemethod == FTPFILE_NOCWD)
+ conn->data->set.ftp_filemethod = FTPFILE_MULTICWD;
+
+ /* try to parse ftp url */
+ ret = ftp_parse_url_path(conn);
+ if(ret) {
+ Curl_safefree(wildcard->pattern);
+ wildcard->tmp_dtor(wildcard->tmp);
+ wildcard->tmp_dtor = ZERO_NULL;
+ wildcard->tmp = NULL;
+ return ret;
+ }
+
+ wildcard->path = strdup(conn->data->state.path);
+ if(!wildcard->path) {
+ Curl_safefree(wildcard->pattern);
+ wildcard->tmp_dtor(wildcard->tmp);
+ wildcard->tmp_dtor = ZERO_NULL;
+ wildcard->tmp = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* backup old write_function */
+ ftp_tmp->backup.write_function = conn->data->set.fwrite_func;
+ /* parsing write function */
+ conn->data->set.fwrite_func = Curl_ftp_parselist;
+ /* backup old file descriptor */
+ ftp_tmp->backup.file_descriptor = conn->data->set.out;
+ /* let the writefunc callback know what curl pointer is working with */
+ conn->data->set.out = conn;
+
+ infof(conn->data, "Wildcard - Parsing started\n");
+ return CURLE_OK;
+}
+
+/* This is called recursively */
+static CURLcode wc_statemach(struct connectdata *conn)
+{
+ struct WildcardData * const wildcard = &(conn->data->wildcard);
+ CURLcode ret = CURLE_OK;
+
+ switch (wildcard->state) {
+ case CURLWC_INIT:
+ ret = init_wc_data(conn);
+ if(wildcard->state == CURLWC_CLEAN)
+ /* only listing! */
+ break;
+ else
+ wildcard->state = ret ? CURLWC_ERROR : CURLWC_MATCHING;
+ break;
+
+ case CURLWC_MATCHING: {
+ /* In this state is LIST response successfully parsed, so lets restore
+ previous WRITEFUNCTION callback and WRITEDATA pointer */
+ struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
+ conn->data->set.fwrite_func = ftp_tmp->backup.write_function;
+ conn->data->set.out = ftp_tmp->backup.file_descriptor;
+ ftp_tmp->backup.write_function = ZERO_NULL;
+ ftp_tmp->backup.file_descriptor = NULL;
+ wildcard->state = CURLWC_DOWNLOADING;
+
+ if(Curl_ftp_parselist_geterror(ftp_tmp->parser)) {
+ /* error found in LIST parsing */
+ wildcard->state = CURLWC_CLEAN;
+ return wc_statemach(conn);
+ }
+ else if(wildcard->filelist->size == 0) {
+ /* no corresponding file */
+ wildcard->state = CURLWC_CLEAN;
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+ }
+ return wc_statemach(conn);
+ }
+
+ case CURLWC_DOWNLOADING: {
+ /* filelist has at least one file, lets get first one */
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ struct curl_fileinfo *finfo = wildcard->filelist->head->ptr;
+
+ char *tmp_path = aprintf("%s%s", wildcard->path, finfo->filename);
+ if(!tmp_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* switch default "state.pathbuffer" and tmp_path, good to see
+ ftp_parse_url_path function to understand this trick */
+ Curl_safefree(conn->data->state.pathbuffer);
+ conn->data->state.pathbuffer = tmp_path;
+ conn->data->state.path = tmp_path;
+
+ infof(conn->data, "Wildcard - START of \"%s\"\n", finfo->filename);
+ if(conn->data->set.chunk_bgn) {
+ long userresponse = conn->data->set.chunk_bgn(
+ finfo, wildcard->customptr, (int)wildcard->filelist->size);
+ switch(userresponse) {
+ case CURL_CHUNK_BGN_FUNC_SKIP:
+ infof(conn->data, "Wildcard - \"%s\" skipped by user\n",
+ finfo->filename);
+ wildcard->state = CURLWC_SKIP;
+ return wc_statemach(conn);
+ case CURL_CHUNK_BGN_FUNC_FAIL:
+ return CURLE_CHUNK_FAILED;
+ }
+ }
+
+ if(finfo->filetype != CURLFILETYPE_FILE) {
+ wildcard->state = CURLWC_SKIP;
+ return wc_statemach(conn);
+ }
+
+ if(finfo->flags & CURLFINFOFLAG_KNOWN_SIZE)
+ ftpc->known_filesize = finfo->size;
+
+ ret = ftp_parse_url_path(conn);
+ if(ret) {
+ return ret;
+ }
+
+ /* we don't need the Curl_fileinfo of first file anymore */
+ Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
+
+ if(wildcard->filelist->size == 0) { /* remains only one file to down. */
+ wildcard->state = CURLWC_CLEAN;
+ /* after that will be ftp_do called once again and no transfer
+ will be done because of CURLWC_CLEAN state */
+ return CURLE_OK;
+ }
+ } break;
+
+ case CURLWC_SKIP: {
+ if(conn->data->set.chunk_end)
+ conn->data->set.chunk_end(conn->data->wildcard.customptr);
+ Curl_llist_remove(wildcard->filelist, wildcard->filelist->head, NULL);
+ wildcard->state = (wildcard->filelist->size == 0) ?
+ CURLWC_CLEAN : CURLWC_DOWNLOADING;
+ return wc_statemach(conn);
+ }
+
+ case CURLWC_CLEAN: {
+ struct ftp_wc_tmpdata *ftp_tmp = wildcard->tmp;
+ ret = CURLE_OK;
+ if(ftp_tmp) {
+ ret = Curl_ftp_parselist_geterror(ftp_tmp->parser);
+ }
+ wildcard->state = ret ? CURLWC_ERROR : CURLWC_DONE;
+ } break;
+
+ case CURLWC_DONE:
+ case CURLWC_ERROR:
+ break;
+ }
+
+ return ret;
+}
+
+/***********************************************************************
+ *
+ * ftp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (ftp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode ftp_do(struct connectdata *conn, bool *done)
+{
+ CURLcode retcode = CURLE_OK;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ *done = FALSE; /* default to false */
+ ftpc->wait_data_conn = FALSE; /* default to no such wait */
+
+ if(conn->data->set.wildcardmatch) {
+ retcode = wc_statemach(conn);
+ if(conn->data->wildcard.state == CURLWC_SKIP ||
+ conn->data->wildcard.state == CURLWC_DONE) {
+ /* do not call ftp_regular_transfer */
+ return CURLE_OK;
+ }
+ if(retcode) /* error, loop or skipping the file */
+ return retcode;
+ }
+ else { /* no wildcard FSM needed */
+ retcode = ftp_parse_url_path(conn);
+ if(retcode)
+ return retcode;
+ }
+
+ retcode = ftp_regular_transfer(conn, done);
+
+ return retcode;
+}
+
+
+CURLcode Curl_ftpsendf(struct connectdata *conn,
+ const char *fmt, ...)
+{
+ ssize_t bytes_written;
+#define SBUF_SIZE 1024
+ char s[SBUF_SIZE];
+ size_t write_len;
+ char *sptr=s;
+ CURLcode res = CURLE_OK;
+#ifdef HAVE_GSSAPI
+ enum protection_level data_sec = conn->data_prot;
+#endif
+
+ va_list ap;
+ va_start(ap, fmt);
+ write_len = vsnprintf(s, SBUF_SIZE-3, fmt, ap);
+ va_end(ap);
+
+ strcpy(&s[write_len], "\r\n"); /* append a trailing CRLF */
+ write_len +=2;
+
+ bytes_written=0;
+
+ res = Curl_convert_to_network(conn->data, s, write_len);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(res)
+ return(res);
+
+ for(;;) {
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CMD;
+#endif
+ res = Curl_write(conn, conn->sock[FIRSTSOCKET], sptr, write_len,
+ &bytes_written);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+ conn->data_prot = data_sec;
+#endif
+
+ if(CURLE_OK != res)
+ break;
+
+ if(conn->data->set.verbose)
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+ sptr, (size_t)bytes_written, conn);
+
+ if(bytes_written != (ssize_t)write_len) {
+ write_len -= bytes_written;
+ sptr += bytes_written;
+ }
+ else
+ break;
+ }
+
+ return res;
+}
+
+/***********************************************************************
+ *
+ * ftp_quit()
+ *
+ * This should be called before calling sclose() on an ftp control connection
+ * (not data connections). We should then wait for the response from the
+ * server before returning. The calling code should then try to close the
+ * connection.
+ *
+ */
+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, "%s", "QUIT");
+ if(result) {
+ failf(conn->data, "Failure sending QUIT command: %s",
+ curl_easy_strerror(result));
+ conn->proto.ftpc.ctl_valid = FALSE; /* mark control connection as bad */
+ conn->bits.close = TRUE; /* mark for connection closure */
+ state(conn, FTP_STOP);
+ return result;
+ }
+
+ state(conn, FTP_QUIT);
+
+ result = ftp_block_statemach(conn);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_disconnect()
+ *
+ * Disconnect from an FTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode ftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct ftp_conn *ftpc= &conn->proto.ftpc;
+ struct pingpong *pp = &ftpc->pp;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to.
+
+ ftp_quit() will check the state of ftp->ctl_valid. If it's ok it
+ will try to send the QUIT command, otherwise it will just return.
+ */
+ if(dead_connection)
+ ftpc->ctl_valid = FALSE;
+
+ /* The FTP session may or may not have been allocated/setup at this point! */
+ (void)ftp_quit(conn); /* ignore errors on the QUIT */
+
+ if(ftpc->entrypath) {
+ struct SessionHandle *data = conn->data;
+ if(data->state.most_recent_ftp_entrypath == ftpc->entrypath) {
+ data->state.most_recent_ftp_entrypath = NULL;
+ }
+ free(ftpc->entrypath);
+ ftpc->entrypath = NULL;
+ }
+
+ freedirs(ftpc);
+ if(ftpc->prevpath) {
+ free(ftpc->prevpath);
+ ftpc->prevpath = NULL;
+ }
+ if(ftpc->server_os) {
+ free(ftpc->server_os);
+ ftpc->server_os = NULL;
+ }
+
+ Curl_pp_disconnect(pp);
+
+#ifdef HAVE_GSSAPI
+ Curl_sec_end(conn);
+#endif
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * ftp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static
+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->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;
+ const char *cur_pos;
+ const char *filename = NULL;
+
+ cur_pos = path_to_use; /* current position in path. point at the begin
+ of next path component */
+
+ ftpc->ctl_valid = FALSE;
+ ftpc->cwdfail = FALSE;
+
+ switch(data->set.ftp_filemethod) {
+ case FTPFILE_NOCWD:
+ /* fastest, but less standard-compliant */
+
+ /*
+ The best time to check whether the path is a file or directory is right
+ here. so:
+
+ the first condition in the if() right here, is there just in case
+ someone decides to set path to NULL one day
+ */
+ if(data->state.path &&
+ data->state.path[0] &&
+ (data->state.path[strlen(data->state.path) - 1] != '/') )
+ filename = data->state.path; /* this is a full file path */
+ /*
+ ftpc->file is not used anywhere other than for operations on a file.
+ In other words, never for directory operations.
+ So we can safely leave filename as NULL here and use it as a
+ argument in dir/file decisions.
+ */
+ break;
+
+ case FTPFILE_SINGLECWD:
+ /* get the last slash */
+ if(!path_to_use[0]) {
+ /* no dir, no file */
+ ftpc->dirdepth = 0;
+ break;
+ }
+ 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_uztosi(dirlen) : 1,
+ NULL);
+ if(!ftpc->dirs[0]) {
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ftpc->dirdepth = 1; /* we consider it to be a single dir */
+ filename = slash_pos ? slash_pos+1 : cur_pos; /* rest is file name */
+ }
+ else
+ filename = cur_pos; /* this is a file name only */
+ break;
+
+ default: /* allow pretty much anything */
+ case FTPFILE_MULTICWD:
+ ftpc->dirdepth = 0;
+ ftpc->diralloc = 5; /* default dir depth to allocate */
+ ftpc->dirs = calloc(ftpc->diralloc, sizeof(ftpc->dirs[0]));
+ if(!ftpc->dirs)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* we have a special case for listing the root dir only */
+ if(strequal(path_to_use, "/")) {
+ cur_pos++; /* make it point to the zero byte */
+ ftpc->dirs[0] = strdup("/");
+ ftpc->dirdepth++;
+ }
+ else {
+ /* parse the URL path into separate path components */
+ while((slash_pos = strchr(cur_pos, '/')) != NULL) {
+ /* 1 or 0 pointer offset to indicate absolute directory */
+ ssize_t absolute_dir = ((cur_pos - data->state.path > 0) &&
+ (ftpc->dirdepth == 0))?1:0;
+
+ /* seek out the next path component */
+ if(slash_pos-cur_pos) {
+ /* we skip empty path components, like "x//y" since the FTP command
+ CWD requires a parameter and a non-existent parameter a) doesn't
+ work on many servers and b) has no effect on the others. */
+ int len = curlx_sztosi(slash_pos - cur_pos + absolute_dir);
+ ftpc->dirs[ftpc->dirdepth] =
+ curl_easy_unescape(conn->data, cur_pos - absolute_dir, len, NULL);
+ if(!ftpc->dirs[ftpc->dirdepth]) { /* run out of memory ... */
+ failf(data, "no memory");
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(isBadFtpString(ftpc->dirs[ftpc->dirdepth])) {
+ free(ftpc->dirs[ftpc->dirdepth]);
+ freedirs(ftpc);
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+ 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;
+ }
+
+ cur_pos = slash_pos + 1; /* jump to the rest of the string */
+ if(++ftpc->dirdepth >= ftpc->diralloc) {
+ /* enlarge array */
+ char **bigger;
+ ftpc->diralloc *= 2; /* double the size each time */
+ bigger = realloc(ftpc->dirs, ftpc->diralloc * sizeof(ftpc->dirs[0]));
+ if(!bigger) {
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ ftpc->dirs = bigger;
+ }
+ }
+ }
+ filename = cur_pos; /* the rest is the file name */
+ break;
+ } /* switch */
+
+ if(filename && *filename) {
+ ftpc->file = curl_easy_unescape(conn->data, filename, 0, NULL);
+ if(NULL == ftpc->file) {
+ freedirs(ftpc);
+ failf(data, "no memory");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(isBadFtpString(ftpc->file)) {
+ freedirs(ftpc);
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+ else
+ ftpc->file=NULL; /* instead of point to a zero byte, we make it a NULL
+ pointer */
+
+ if(data->set.upload && !ftpc->file && (ftp->transfer == FTPTRANSFER_BODY)) {
+ /* We need a file name when uploading. Return error! */
+ failf(data, "Uploading to a URL without a file name!");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ ftpc->cwddone = FALSE; /* default to not done */
+
+ if(ftpc->prevpath) {
+ /* prevpath is "raw" so we convert the input path before we compare the
+ strings */
+ int dlen;
+ char *path = curl_easy_unescape(conn->data, data->state.path, 0, &dlen);
+ if(!path) {
+ freedirs(ftpc);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ dlen -= ftpc->file?curlx_uztosi(strlen(ftpc->file)):0;
+ if((dlen == curlx_uztosi(strlen(ftpc->prevpath))) &&
+ strnequal(path, ftpc->prevpath, dlen)) {
+ infof(data, "Request has same path as previous transfer\n");
+ ftpc->cwddone = TRUE;
+ }
+ free(path);
+ }
+
+ return CURLE_OK;
+}
+
+/* call this when the DO phase has completed */
+static CURLcode ftp_dophase_done(struct connectdata *conn,
+ bool connected)
+{
+ struct FTP *ftp = conn->data->req.protop;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+
+ if(connected) {
+ int completed;
+ CURLcode result = ftp_do_more(conn, &completed);
+
+ if(result) {
+ if(conn->sock[SECONDARYSOCKET] != CURL_SOCKET_BAD) {
+ /* close the second socket if it was created already */
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD;
+ }
+ return result;
+ }
+ }
+
+ if(ftp->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ else if(!connected)
+ /* since we didn't connect now, we want do_more to get called */
+ conn->bits.do_more = TRUE;
+
+ ftpc->ctl_valid = TRUE; /* seems good */
+
+ return CURLE_OK;
+}
+
+/* called from multi.c while DOing */
+static CURLcode ftp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = ftp_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = ftp_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete2\n"));
+ }
+ return result;
+}
+
+/***********************************************************************
+ *
+ * ftp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ *
+ * ftp->ctl_valid starts out as FALSE, and gets set to TRUE if we reach the
+ * ftp_done() function without finding any major problem.
+ */
+static
+CURLcode ftp_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result=CURLE_OK;
+ bool connected=FALSE;
+ struct SessionHandle *data = conn->data;
+ struct ftp_conn *ftpc = &conn->proto.ftpc;
+ data->req.size = -1; /* make sure this is unknown at this point */
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ ftpc->ctl_valid = TRUE; /* starts good */
+
+ result = ftp_perform(conn,
+ &connected, /* have we connected after PASV/PORT */
+ dophase_done); /* all commands in the DO-phase done? */
+
+ if(CURLE_OK == result) {
+
+ if(!*dophase_done)
+ /* the DO phase has not completed yet */
+ return CURLE_OK;
+
+ result = ftp_dophase_done(conn, connected);
+
+ if(result)
+ return result;
+ }
+ else
+ freedirs(ftpc);
+
+ return result;
+}
+
+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
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_ftp)
+ conn->handler = &Curl_handler_ftp_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_ftps_proxy;
+#else
+ failf(data, "FTPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+ /* 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 */
+
+ /* FTP URLs support an extension like ";type=<typecode>" that
+ * we'll try to get now! */
+ type = strstr(data->state.path, ";type=");
+
+ if(!type)
+ type = strstr(conn->host.rawalloc, ";type=");
+
+ if(type) {
+ *type = 0; /* it was in the middle of the hostname */
+ command = Curl_raw_toupper(type[6]);
+ conn->bits.type_set = TRUE;
+
+ switch (command) {
+ case 'A': /* ASCII mode */
+ data->set.prefer_ascii = TRUE;
+ break;
+
+ case 'D': /* directory mode */
+ data->set.ftp_list_only = TRUE;
+ break;
+
+ case 'I': /* binary mode */
+ default:
+ /* switch off ASCII */
+ data->set.prefer_ascii = FALSE;
+ break;
+ }
+ }
+
+ /* 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;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/libs/libcurl/src/ftp.h b/libs/libcurl/src/ftp.h
new file mode 100644
index 0000000000..bdd59c93da
--- /dev/null
+++ b/libs/libcurl/src/ftp.h
@@ -0,0 +1,154 @@
+#ifndef HEADER_CURL_FTP_H
+#define HEADER_CURL_FTP_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 "pingpong.h"
+
+#ifndef CURL_DISABLE_FTP
+extern const struct Curl_handler Curl_handler_ftp;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_ftps;
+#endif
+
+CURLcode Curl_ftpsendf(struct connectdata *, const char *fmt, ...);
+CURLcode Curl_GetFTPResponse(ssize_t *nread, struct connectdata *conn,
+ int *ftpcode);
+#endif /* CURL_DISABLE_FTP */
+
+/****************************************************************************
+ * FTP unique setup
+ ***************************************************************************/
+typedef enum {
+ FTP_STOP, /* do nothing state, stops the state machine */
+ FTP_WAIT220, /* waiting for the initial 220 response immediately after
+ a connect */
+ FTP_AUTH,
+ FTP_USER,
+ FTP_PASS,
+ FTP_ACCT,
+ FTP_PBSZ,
+ FTP_PROT,
+ FTP_CCC,
+ FTP_PWD,
+ FTP_SYST,
+ FTP_NAMEFMT,
+ FTP_QUOTE, /* waiting for a response to a command sent in a quote list */
+ FTP_RETR_PREQUOTE,
+ FTP_STOR_PREQUOTE,
+ FTP_POSTQUOTE,
+ FTP_CWD, /* change dir */
+ FTP_MKD, /* if the dir didn't exist */
+ FTP_MDTM, /* to figure out the datestamp */
+ FTP_TYPE, /* to set type when doing a head-like request */
+ FTP_LIST_TYPE, /* set type when about to do a dir list */
+ FTP_RETR_TYPE, /* set type when about to RETR a file */
+ FTP_STOR_TYPE, /* set type when about to STOR a file */
+ FTP_SIZE, /* get the remote file's size for head-like request */
+ FTP_RETR_SIZE, /* get the remote file's size for RETR */
+ FTP_STOR_SIZE, /* get the size for STOR */
+ FTP_REST, /* when used to check if the server supports it in head-like */
+ FTP_RETR_REST, /* when asking for "resume" in for RETR */
+ FTP_PORT, /* generic state for PORT, LPRT and EPRT, check count1 */
+ FTP_PRET, /* generic state for PRET RETR, PRET STOR and PRET LIST/NLST */
+ FTP_PASV, /* generic state for PASV and EPSV, check count1 */
+ FTP_LIST, /* generic state for LIST, NLST or a custom list command */
+ FTP_RETR,
+ FTP_STOR, /* generic state for STOR and APPE */
+ FTP_QUIT,
+ FTP_LAST /* never used */
+} ftpstate;
+
+struct ftp_parselist_data; /* defined later in ftplistparser.c */
+
+struct ftp_wc_tmpdata {
+ struct ftp_parselist_data *parser;
+
+ struct {
+ curl_write_callback write_function;
+ FILE *file_descriptor;
+ } backup;
+};
+
+typedef enum {
+ FTPFILE_MULTICWD = 1, /* as defined by RFC1738 */
+ FTPFILE_NOCWD = 2, /* use SIZE / RETR / STOR on the full path */
+ FTPFILE_SINGLECWD = 3 /* make one CWD, then SIZE / RETR / STOR on the
+ file */
+} curl_ftpfile;
+
+/* This FTP struct is used in the SessionHandle. All FTP data that is
+ connection-oriented must be in FTP_conn to properly deal with the fact that
+ perhaps the SessionHandle is changed between the times the connection is
+ used. */
+struct FTP {
+ curl_off_t *bytecountp;
+ char *user; /* user name string */
+ char *passwd; /* password string */
+
+ /* transfer a file/body or not, done as a typedefed enum just to make
+ debuggers display the full symbol and not just the numerical value */
+ curl_pp_transfer transfer;
+ curl_off_t downloadsize;
+};
+
+
+/* ftp_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct ftp_conn {
+ struct pingpong pp;
+ char *entrypath; /* the PWD reply when we logged on */
+ char **dirs; /* realloc()ed array for path components */
+ int dirdepth; /* number of entries used in the 'dirs' array */
+ int diralloc; /* number of entries allocated for the 'dirs' array */
+ char *file; /* decoded file */
+ bool dont_check; /* Set to TRUE to prevent the final (post-transfer)
+ file size and 226/250 status check. It should still
+ read the line, just ignore the result. */
+ bool ctl_valid; /* Tells Curl_ftp_quit() whether or not to do anything. If
+ the connection has timed out or been closed, this
+ should be FALSE when it gets to Curl_ftp_quit() */
+ bool cwddone; /* if it has been determined that the proper CWD combo
+ already has been done */
+ bool cwdfail; /* set TRUE if a CWD command fails, as then we must prevent
+ caching the current directory */
+ bool wait_data_conn; /* this is set TRUE if data connection is waited */
+ char *prevpath; /* conn->path from the previous transfer */
+ char transfertype; /* set by ftp_transfertype for use by Curl_client_write()a
+ and others (A/I or zero) */
+ int count1; /* general purpose counter for the state machine */
+ int count2; /* general purpose counter for the state machine */
+ int count3; /* general purpose counter for the state machine */
+ ftpstate state; /* always use ftp.c:state() to change state! */
+ ftpstate state_saved; /* transfer type saved to be reloaded after
+ data connection is established */
+ curl_off_t retr_size_saved; /* Size of retrieved file saved */
+ char * server_os; /* The target server operating system. */
+ curl_off_t known_filesize; /* file size is different from -1, if wildcard
+ LIST parsing was done and wc_statemach set
+ it */
+};
+
+#define DEFAULT_ACCEPT_TIMEOUT 60000 /* milliseconds == one minute */
+
+#endif /* HEADER_CURL_FTP_H */
diff --git a/libs/libcurl/src/ftplistparser.c b/libs/libcurl/src/ftplistparser.c
new file mode 100644
index 0000000000..cb3601f58d
--- /dev/null
+++ b/libs/libcurl/src/ftplistparser.c
@@ -0,0 +1,1050 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/**
+ * Now implemented:
+ *
+ * 1) UNIX version 1
+ * drwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog
+ * 2) UNIX version 2
+ * drwxr-xr-x 1 user01 ftp 512 Jan 29 1997 prog
+ * 3) UNIX version 3
+ * drwxr-xr-x 1 1 1 512 Jan 29 23:32 prog
+ * 4) UNIX symlink
+ * lrwxr-xr-x 1 user01 ftp 512 Jan 29 23:32 prog -> prog2000
+ * 5) DOS style
+ * 01-29-97 11:32PM <DIR> prog
+ */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "fileinfo.h"
+#include "llist.h"
+#include "strtoofft.h"
+#include "rawstr.h"
+#include "ftp.h"
+#include "ftplistparser.h"
+#include "curl_fnmatch.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"
+
+/* allocs buffer which will contain one line of LIST command response */
+#define FTP_BUFFER_ALLOCSIZE 160
+
+typedef enum {
+ PL_UNIX_TOTALSIZE = 0,
+ PL_UNIX_FILETYPE,
+ PL_UNIX_PERMISSION,
+ PL_UNIX_HLINKS,
+ PL_UNIX_USER,
+ PL_UNIX_GROUP,
+ PL_UNIX_SIZE,
+ PL_UNIX_TIME,
+ PL_UNIX_FILENAME,
+ PL_UNIX_SYMLINK
+} pl_unix_mainstate;
+
+typedef union {
+ enum {
+ PL_UNIX_TOTALSIZE_INIT = 0,
+ PL_UNIX_TOTALSIZE_READING
+ } total_dirsize;
+
+ enum {
+ PL_UNIX_HLINKS_PRESPACE = 0,
+ PL_UNIX_HLINKS_NUMBER
+ } hlinks;
+
+ enum {
+ PL_UNIX_USER_PRESPACE = 0,
+ PL_UNIX_USER_PARSING
+ } user;
+
+ enum {
+ PL_UNIX_GROUP_PRESPACE = 0,
+ PL_UNIX_GROUP_NAME
+ } group;
+
+ enum {
+ PL_UNIX_SIZE_PRESPACE = 0,
+ PL_UNIX_SIZE_NUMBER
+ } size;
+
+ enum {
+ PL_UNIX_TIME_PREPART1 = 0,
+ PL_UNIX_TIME_PART1,
+ PL_UNIX_TIME_PREPART2,
+ PL_UNIX_TIME_PART2,
+ PL_UNIX_TIME_PREPART3,
+ PL_UNIX_TIME_PART3
+ } time;
+
+ enum {
+ PL_UNIX_FILENAME_PRESPACE = 0,
+ PL_UNIX_FILENAME_NAME,
+ PL_UNIX_FILENAME_WINDOWSEOL
+ } filename;
+
+ enum {
+ PL_UNIX_SYMLINK_PRESPACE = 0,
+ PL_UNIX_SYMLINK_NAME,
+ PL_UNIX_SYMLINK_PRETARGET1,
+ PL_UNIX_SYMLINK_PRETARGET2,
+ PL_UNIX_SYMLINK_PRETARGET3,
+ PL_UNIX_SYMLINK_PRETARGET4,
+ PL_UNIX_SYMLINK_TARGET,
+ PL_UNIX_SYMLINK_WINDOWSEOL
+ } symlink;
+} pl_unix_substate;
+
+typedef enum {
+ PL_WINNT_DATE = 0,
+ PL_WINNT_TIME,
+ PL_WINNT_DIRORSIZE,
+ PL_WINNT_FILENAME
+} pl_winNT_mainstate;
+
+typedef union {
+ enum {
+ PL_WINNT_TIME_PRESPACE = 0,
+ PL_WINNT_TIME_TIME
+ } time;
+ enum {
+ PL_WINNT_DIRORSIZE_PRESPACE = 0,
+ PL_WINNT_DIRORSIZE_CONTENT
+ } dirorsize;
+ enum {
+ PL_WINNT_FILENAME_PRESPACE = 0,
+ PL_WINNT_FILENAME_CONTENT,
+ PL_WINNT_FILENAME_WINEOL
+ } filename;
+} pl_winNT_substate;
+
+/* This struct is used in wildcard downloading - for parsing LIST response */
+struct ftp_parselist_data {
+ enum {
+ OS_TYPE_UNKNOWN = 0,
+ OS_TYPE_UNIX,
+ OS_TYPE_WIN_NT
+ } os_type;
+
+ union {
+ struct {
+ pl_unix_mainstate main;
+ pl_unix_substate sub;
+ } UNIX;
+
+ struct {
+ pl_winNT_mainstate main;
+ pl_winNT_substate sub;
+ } NT;
+ } state;
+
+ CURLcode error;
+ struct curl_fileinfo *file_data;
+ unsigned int item_length;
+ size_t item_offset;
+ struct {
+ size_t filename;
+ size_t user;
+ size_t group;
+ size_t time;
+ size_t perm;
+ size_t symlink_target;
+ } offsets;
+};
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void)
+{
+ return calloc(1, sizeof(struct ftp_parselist_data));
+}
+
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data)
+{
+ if(*pl_data)
+ free(*pl_data);
+ *pl_data = NULL;
+}
+
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data)
+{
+ return pl_data->error;
+}
+
+
+#define FTP_LP_MALFORMATED_PERM 0x01000000
+
+static int ftp_pl_get_permission(const char *str)
+{
+ int permissions = 0;
+ /* USER */
+ if(str[0] == 'r')
+ permissions |= 1 << 8;
+ else if(str[0] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[1] == 'w')
+ permissions |= 1 << 7;
+ else if(str[1] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+
+ if(str[2] == 'x')
+ permissions |= 1 << 6;
+ else if(str[2] == 's') {
+ permissions |= 1 << 6;
+ permissions |= 1 << 11;
+ }
+ else if(str[2] == 'S')
+ permissions |= 1 << 11;
+ else if(str[2] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ /* GROUP */
+ if(str[3] == 'r')
+ permissions |= 1 << 5;
+ else if(str[3] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[4] == 'w')
+ permissions |= 1 << 4;
+ else if(str[4] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[5] == 'x')
+ permissions |= 1 << 3;
+ else if(str[5] == 's') {
+ permissions |= 1 << 3;
+ permissions |= 1 << 10;
+ }
+ else if(str[5] == 'S')
+ permissions |= 1 << 10;
+ else if(str[5] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ /* others */
+ if(str[6] == 'r')
+ permissions |= 1 << 2;
+ else if(str[6] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[7] == 'w')
+ permissions |= 1 << 1;
+ else if(str[7] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+ if(str[8] == 'x')
+ permissions |= 1;
+ else if(str[8] == 't') {
+ permissions |= 1;
+ permissions |= 1 << 9;
+ }
+ else if(str[8] == 'T')
+ permissions |= 1 << 9;
+ else if(str[8] != '-')
+ permissions |= FTP_LP_MALFORMATED_PERM;
+
+ return permissions;
+}
+
+static void PL_ERROR(struct connectdata *conn, CURLcode err)
+{
+ struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ if(parser->file_data)
+ Curl_fileinfo_dtor(NULL, parser->file_data);
+ parser->file_data = NULL;
+ parser->error = err;
+}
+
+static bool ftp_pl_gettime(struct ftp_parselist_data *parser, char *string)
+{
+ (void)parser;
+ (void)string;
+ /* TODO
+ * There could be possible parse timestamp from server. Leaving unimplemented
+ * for now.
+ * If you want implement this, please add CURLFINFOFLAG_KNOWN_TIME flag to
+ * parser->file_data->flags
+ *
+ * Ftp servers are giving usually these formats:
+ * Apr 11 1998 (unknown time.. set it to 00:00:00?)
+ * Apr 11 12:21 (unknown year -> set it to NOW() time?)
+ * 08-05-09 02:49PM (ms-dos format)
+ * 20100421092538 -> for MLST/MLSD response
+ */
+
+ return FALSE;
+}
+
+static CURLcode ftp_pl_insert_finfo(struct connectdata *conn,
+ struct curl_fileinfo *finfo)
+{
+ curl_fnmatch_callback compare;
+ struct WildcardData *wc = &conn->data->wildcard;
+ struct ftp_wc_tmpdata *tmpdata = wc->tmp;
+ struct curl_llist *llist = wc->filelist;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ bool add = TRUE;
+
+ /* move finfo pointers to b_data */
+ char *str = finfo->b_data;
+ finfo->filename = str + parser->offsets.filename;
+ finfo->strings.group = parser->offsets.group ?
+ str + parser->offsets.group : NULL;
+ finfo->strings.perm = parser->offsets.perm ?
+ str + parser->offsets.perm : NULL;
+ finfo->strings.target = parser->offsets.symlink_target ?
+ str + parser->offsets.symlink_target : NULL;
+ finfo->strings.time = str + parser->offsets.time;
+ finfo->strings.user = parser->offsets.user ?
+ str + parser->offsets.user : NULL;
+
+ /* get correct fnmatch callback */
+ compare = conn->data->set.fnmatch;
+ if(!compare)
+ compare = Curl_fnmatch;
+
+ /* filter pattern-corresponding filenames */
+ if(compare(conn->data->set.fnmatch_data, wc->pattern,
+ finfo->filename) == 0) {
+ /* discard symlink which is containing multiple " -> " */
+ if((finfo->filetype == CURLFILETYPE_SYMLINK) && finfo->strings.target &&
+ (strstr(finfo->strings.target, " -> "))) {
+ add = FALSE;
+ }
+ }
+ else {
+ add = FALSE;
+ }
+
+ if(add) {
+ if(!Curl_llist_insert_next(llist, llist->tail, finfo)) {
+ Curl_fileinfo_dtor(NULL, finfo);
+ tmpdata->parser->file_data = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else {
+ Curl_fileinfo_dtor(NULL, finfo);
+ }
+
+ tmpdata->parser->file_data = NULL;
+ return CURLE_OK;
+}
+
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+ void *connptr)
+{
+ size_t bufflen = size*nmemb;
+ struct connectdata *conn = (struct connectdata *)connptr;
+ struct ftp_wc_tmpdata *tmpdata = conn->data->wildcard.tmp;
+ struct ftp_parselist_data *parser = tmpdata->parser;
+ struct curl_fileinfo *finfo;
+ unsigned long i = 0;
+ CURLcode rc;
+
+ if(parser->error) { /* error in previous call */
+ /* scenario:
+ * 1. call => OK..
+ * 2. call => OUT_OF_MEMORY (or other error)
+ * 3. (last) call => is skipped RIGHT HERE and the error is hadled later
+ * in wc_statemach()
+ */
+ return bufflen;
+ }
+
+ if(parser->os_type == OS_TYPE_UNKNOWN && bufflen > 0) {
+ /* considering info about FILE response format */
+ parser->os_type = (buffer[0] >= '0' && buffer[0] <= '9') ?
+ OS_TYPE_WIN_NT : OS_TYPE_UNIX;
+ }
+
+ while(i < bufflen) { /* FSM */
+
+ char c = buffer[i];
+ if(!parser->file_data) { /* tmp file data is not allocated yet */
+ parser->file_data = Curl_fileinfo_alloc();
+ if(!parser->file_data) {
+ parser->error = CURLE_OUT_OF_MEMORY;
+ return bufflen;
+ }
+ parser->file_data->b_data = malloc(FTP_BUFFER_ALLOCSIZE);
+ if(!parser->file_data->b_data) {
+ PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
+ return bufflen;
+ }
+ parser->file_data->b_size = FTP_BUFFER_ALLOCSIZE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+
+ finfo = parser->file_data;
+ finfo->b_data[finfo->b_used++] = c;
+
+ if(finfo->b_used >= finfo->b_size - 1) {
+ /* if it is important, extend buffer space for file data */
+ char *tmp = realloc(finfo->b_data,
+ finfo->b_size + FTP_BUFFER_ALLOCSIZE);
+ if(tmp) {
+ finfo->b_size += FTP_BUFFER_ALLOCSIZE;
+ finfo->b_data = tmp;
+ }
+ else {
+ Curl_fileinfo_dtor(NULL, parser->file_data);
+ parser->file_data = NULL;
+ parser->error = CURLE_OUT_OF_MEMORY;
+ PL_ERROR(conn, CURLE_OUT_OF_MEMORY);
+ return bufflen;
+ }
+ }
+
+ switch (parser->os_type) {
+ case OS_TYPE_UNIX:
+ switch (parser->state.UNIX.main) {
+ case PL_UNIX_TOTALSIZE:
+ switch(parser->state.UNIX.sub.total_dirsize) {
+ case PL_UNIX_TOTALSIZE_INIT:
+ if(c == 't') {
+ parser->state.UNIX.sub.total_dirsize = PL_UNIX_TOTALSIZE_READING;
+ parser->item_length++;
+ }
+ else {
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ /* start FSM again not considering size of directory */
+ finfo->b_used = 0;
+ i--;
+ }
+ break;
+ case PL_UNIX_TOTALSIZE_READING:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->item_length--;
+ finfo->b_used--;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_length - 1] = 0;
+ if(strncmp("total ", finfo->b_data, 6) == 0) {
+ char *endptr = finfo->b_data+6;
+ /* here we can deal with directory size */
+ while(ISSPACE(*endptr))
+ endptr++;
+ if(*endptr != 0) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ finfo->b_used = 0;
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_FILETYPE:
+ switch (c) {
+ case '-':
+ finfo->filetype = CURLFILETYPE_FILE;
+ break;
+ case 'd':
+ finfo->filetype = CURLFILETYPE_DIRECTORY;
+ break;
+ case 'l':
+ finfo->filetype = CURLFILETYPE_SYMLINK;
+ break;
+ case 'p':
+ finfo->filetype = CURLFILETYPE_NAMEDPIPE;
+ break;
+ case 's':
+ finfo->filetype = CURLFILETYPE_SOCKET;
+ break;
+ case 'c':
+ finfo->filetype = CURLFILETYPE_DEVICE_CHAR;
+ break;
+ case 'b':
+ finfo->filetype = CURLFILETYPE_DEVICE_BLOCK;
+ break;
+ case 'D':
+ finfo->filetype = CURLFILETYPE_DOOR;
+ break;
+ default:
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_PERMISSION;
+ parser->item_length = 0;
+ parser->item_offset = 1;
+ break;
+ case PL_UNIX_PERMISSION:
+ parser->item_length++;
+ if(parser->item_length <= 9) {
+ if(!strchr("rwx-tTsS", c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else if(parser->item_length == 10) {
+ unsigned int perm;
+ if(c != ' ') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ finfo->b_data[10] = 0; /* terminate permissions */
+ perm = ftp_pl_get_permission(finfo->b_data + parser->item_offset);
+ if(perm & FTP_LP_MALFORMATED_PERM) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_PERM;
+ parser->file_data->perm = perm;
+ parser->offsets.perm = parser->item_offset;
+
+ parser->item_length = 0;
+ parser->state.UNIX.main = PL_UNIX_HLINKS;
+ parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_PRESPACE;
+ }
+ break;
+ case PL_UNIX_HLINKS:
+ switch(parser->state.UNIX.sub.hlinks) {
+ case PL_UNIX_HLINKS_PRESPACE:
+ if(c != ' ') {
+ if(c >= '0' && c <= '9') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.hlinks = PL_UNIX_HLINKS_NUMBER;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_HLINKS_NUMBER:
+ parser->item_length ++;
+ if(c == ' ') {
+ char *p;
+ long int hlinks;
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ hlinks = strtol(finfo->b_data + parser->item_offset, &p, 10);
+ if(p[0] == '\0' && hlinks != LONG_MAX && hlinks != LONG_MIN) {
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_HLINKCOUNT;
+ parser->file_data->hardlinks = hlinks;
+ }
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ parser->state.UNIX.main = PL_UNIX_USER;
+ parser->state.UNIX.sub.user = PL_UNIX_USER_PRESPACE;
+ }
+ else if(c < '0' || c > '9') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_USER:
+ switch(parser->state.UNIX.sub.user) {
+ case PL_UNIX_USER_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.user = PL_UNIX_USER_PARSING;
+ }
+ break;
+ case PL_UNIX_USER_PARSING:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.user = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_GROUP;
+ parser->state.UNIX.sub.group = PL_UNIX_GROUP_PRESPACE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_GROUP:
+ switch(parser->state.UNIX.sub.group) {
+ case PL_UNIX_GROUP_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.group = PL_UNIX_GROUP_NAME;
+ }
+ break;
+ case PL_UNIX_GROUP_NAME:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.group = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_SIZE;
+ parser->state.UNIX.sub.size = PL_UNIX_SIZE_PRESPACE;
+ parser->item_offset = 0;
+ parser->item_length = 0;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_SIZE:
+ switch(parser->state.UNIX.sub.size) {
+ case PL_UNIX_SIZE_PRESPACE:
+ if(c != ' ') {
+ if(c >= '0' && c <= '9') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.size = PL_UNIX_SIZE_NUMBER;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_SIZE_NUMBER:
+ parser->item_length++;
+ if(c == ' ') {
+ char *p;
+ curl_off_t fsize;
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ fsize = curlx_strtoofft(finfo->b_data+parser->item_offset, &p, 10);
+ if(p[0] == '\0' && fsize != CURL_OFF_T_MAX &&
+ fsize != CURL_OFF_T_MIN) {
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
+ parser->file_data->size = fsize;
+ }
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ parser->state.UNIX.main = PL_UNIX_TIME;
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART1;
+ }
+ else if(!ISDIGIT(c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_TIME:
+ switch(parser->state.UNIX.sub.time) {
+ case PL_UNIX_TIME_PREPART1:
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->item_offset = finfo->b_used -1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART1;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART1:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART2;
+ }
+ else if(!ISALNUM(c) && c != '.') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_TIME_PREPART2:
+ parser->item_length++;
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART2;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART2:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PREPART3;
+ }
+ else if(!ISALNUM(c) && c != '.') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_TIME_PREPART3:
+ parser->item_length++;
+ if(c != ' ') {
+ if(ISALNUM(c)) {
+ parser->state.UNIX.sub.time = PL_UNIX_TIME_PART3;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_TIME_PART3:
+ parser->item_length++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
+ parser->offsets.time = parser->item_offset;
+ if(ftp_pl_gettime(parser, finfo->b_data + parser->item_offset)) {
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_TIME;
+ }
+ if(finfo->filetype == CURLFILETYPE_SYMLINK) {
+ parser->state.UNIX.main = PL_UNIX_SYMLINK;
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRESPACE;
+ }
+ else {
+ parser->state.UNIX.main = PL_UNIX_FILENAME;
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_PRESPACE;
+ }
+ }
+ else if(!ISALNUM(c) && c != '.' && c != ':') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_FILENAME:
+ switch(parser->state.UNIX.sub.filename) {
+ case PL_UNIX_FILENAME_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_NAME;
+ }
+ break;
+ case PL_UNIX_FILENAME_NAME:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->item_length--;
+ parser->state.UNIX.sub.filename = PL_UNIX_FILENAME_WINDOWSEOL;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ }
+ break;
+ case PL_UNIX_FILENAME_WINDOWSEOL:
+ if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_UNIX_SYMLINK:
+ switch(parser->state.UNIX.sub.symlink) {
+ case PL_UNIX_SYMLINK_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_NAME:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET1;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET1:
+ parser->item_length++;
+ if(c == '-') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET2;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET2:
+ parser->item_length++;
+ if(c == '>') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET3;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET3:
+ parser->item_length++;
+ if(c == ' ') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_PRETARGET4;
+ /* now place where is symlink following */
+ finfo->b_data[parser->item_offset + parser->item_length - 4] = 0;
+ parser->offsets.filename = parser->item_offset;
+ parser->item_length = 0;
+ parser->item_offset = 0;
+ }
+ else if(c == '\r' || c == '\n') {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ else {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_NAME;
+ }
+ break;
+ case PL_UNIX_SYMLINK_PRETARGET4:
+ if(c != '\r' && c != '\n') {
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_TARGET;
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_UNIX_SYMLINK_TARGET:
+ parser->item_length ++;
+ if(c == '\r') {
+ parser->item_length --;
+ parser->state.UNIX.sub.symlink = PL_UNIX_SYMLINK_WINDOWSEOL;
+ }
+ else if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.symlink_target = parser->item_offset;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ }
+ break;
+ case PL_UNIX_SYMLINK_WINDOWSEOL:
+ if(c == '\n') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ parser->offsets.symlink_target = parser->item_offset;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ parser->state.UNIX.main = PL_UNIX_FILETYPE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ case OS_TYPE_WIN_NT:
+ switch(parser->state.NT.main) {
+ case PL_WINNT_DATE:
+ parser->item_length++;
+ if(parser->item_length < 9) {
+ if(!strchr("0123456789-", c)) { /* only simple control */
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else if(parser->item_length == 9) {
+ if(c == ' ') {
+ parser->state.NT.main = PL_WINNT_TIME;
+ parser->state.NT.sub.time = PL_WINNT_TIME_PRESPACE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ case PL_WINNT_TIME:
+ parser->item_length++;
+ switch(parser->state.NT.sub.time) {
+ case PL_WINNT_TIME_PRESPACE:
+ if(!ISSPACE(c)) {
+ parser->state.NT.sub.time = PL_WINNT_TIME_TIME;
+ }
+ break;
+ case PL_WINNT_TIME_TIME:
+ if(c == ' ') {
+ parser->offsets.time = parser->item_offset;
+ finfo->b_data[parser->item_offset + parser->item_length -1] = 0;
+ parser->state.NT.main = PL_WINNT_DIRORSIZE;
+ parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_PRESPACE;
+ parser->item_length = 0;
+ }
+ else if(!strchr("APM0123456789:", c)) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ case PL_WINNT_DIRORSIZE:
+ switch(parser->state.NT.sub.dirorsize) {
+ case PL_WINNT_DIRORSIZE_PRESPACE:
+ if(c == ' ') {
+
+ }
+ else {
+ parser->item_offset = finfo->b_used - 1;
+ parser->item_length = 1;
+ parser->state.NT.sub.dirorsize = PL_WINNT_DIRORSIZE_CONTENT;
+ }
+ break;
+ case PL_WINNT_DIRORSIZE_CONTENT:
+ parser->item_length ++;
+ if(c == ' ') {
+ finfo->b_data[parser->item_offset + parser->item_length - 1] = 0;
+ if(strcmp("<DIR>", finfo->b_data + parser->item_offset) == 0) {
+ finfo->filetype = CURLFILETYPE_DIRECTORY;
+ finfo->size = 0;
+ }
+ else {
+ char *endptr;
+ finfo->size = curlx_strtoofft(finfo->b_data +
+ parser->item_offset,
+ &endptr, 10);
+ if(!*endptr) {
+ if(finfo->size == CURL_OFF_T_MAX ||
+ finfo->size == CURL_OFF_T_MIN) {
+ if(errno == ERANGE) {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ }
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ /* correct file type */
+ parser->file_data->filetype = CURLFILETYPE_FILE;
+ }
+
+ parser->file_data->flags |= CURLFINFOFLAG_KNOWN_SIZE;
+ parser->item_length = 0;
+ parser->state.NT.main = PL_WINNT_FILENAME;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ break;
+ }
+ break;
+ case PL_WINNT_FILENAME:
+ switch (parser->state.NT.sub.filename) {
+ case PL_WINNT_FILENAME_PRESPACE:
+ if(c != ' ') {
+ parser->item_offset = finfo->b_used -1;
+ parser->item_length = 1;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_CONTENT;
+ }
+ break;
+ case PL_WINNT_FILENAME_CONTENT:
+ parser->item_length++;
+ if(c == '\r') {
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_WINEOL;
+ finfo->b_data[finfo->b_used - 1] = 0;
+ }
+ else if(c == '\n') {
+ parser->offsets.filename = parser->item_offset;
+ finfo->b_data[finfo->b_used - 1] = 0;
+ parser->offsets.filename = parser->item_offset;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ parser->state.NT.main = PL_WINNT_DATE;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ break;
+ case PL_WINNT_FILENAME_WINEOL:
+ if(c == '\n') {
+ parser->offsets.filename = parser->item_offset;
+ rc = ftp_pl_insert_finfo(conn, finfo);
+ if(rc) {
+ PL_ERROR(conn, rc);
+ return bufflen;
+ }
+ parser->state.NT.main = PL_WINNT_DATE;
+ parser->state.NT.sub.filename = PL_WINNT_FILENAME_PRESPACE;
+ }
+ else {
+ PL_ERROR(conn, CURLE_FTP_BAD_FILE_LIST);
+ return bufflen;
+ }
+ break;
+ }
+ break;
+ }
+ break;
+ default:
+ return bufflen+1;
+ }
+
+ i++;
+ }
+
+ return bufflen;
+}
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/libs/libcurl/src/ftplistparser.h b/libs/libcurl/src/ftplistparser.h
new file mode 100644
index 0000000000..96764e2a41
--- /dev/null
+++ b/libs/libcurl/src/ftplistparser.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_FTPLISTPARSER_H
+#define HEADER_CURL_FTPLISTPARSER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#ifndef CURL_DISABLE_FTP
+
+/* WRITEFUNCTION callback for parsing LIST responses */
+size_t Curl_ftp_parselist(char *buffer, size_t size, size_t nmemb,
+ void *connptr);
+
+struct ftp_parselist_data; /* defined inside ftplibparser.c */
+
+CURLcode Curl_ftp_parselist_geterror(struct ftp_parselist_data *pl_data);
+
+struct ftp_parselist_data *Curl_ftp_parselist_data_alloc(void);
+
+void Curl_ftp_parselist_data_free(struct ftp_parselist_data **pl_data);
+
+#endif /* CURL_DISABLE_FTP */
+#endif /* HEADER_CURL_FTPLISTPARSER_H */
diff --git a/libs/libcurl/src/getenv.c b/libs/libcurl/src/getenv.c
new file mode 100644
index 0000000000..36215aab0a
--- /dev/null
+++ b/libs/libcurl/src/getenv.c
@@ -0,0 +1,53 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 <curl/curl.h>
+#include "curl_memory.h"
+
+#include "memdebug.h"
+
+static
+char *GetEnv(const char *variable)
+{
+#ifdef _WIN32_WCE
+ return NULL;
+#else
+#ifdef WIN32
+ char env[MAX_PATH]; /* MAX_PATH is from windef.h */
+ char *temp = getenv(variable);
+ env[0] = '\0';
+ if(temp != NULL)
+ ExpandEnvironmentStringsA(temp, env, sizeof(env));
+ return (env[0] != '\0')?strdup(env):NULL;
+#else
+ char *env = getenv(variable);
+ return (env && env[0])?strdup(env):NULL;
+#endif
+#endif
+}
+
+char *curl_getenv(const char *v)
+{
+ return GetEnv(v);
+}
diff --git a/libs/libcurl/src/getinfo.c b/libs/libcurl/src/getinfo.c
new file mode 100644
index 0000000000..3d09dc6846
--- /dev/null
+++ b/libs/libcurl/src/getinfo.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 <curl/curl.h>
+
+#include "urldata.h"
+#include "getinfo.h"
+
+#include "curl_memory.h"
+#include "sslgen.h"
+#include "connect.h" /* Curl_getconnectinfo() */
+#include "progress.h"
+
+/* Make this the last #include */
+#include "memdebug.h"
+
+/*
+ * This is supposed to be called in the beginning of a perform() session
+ * and should reset all session-info variables
+ */
+CURLcode Curl_initinfo(struct SessionHandle *data)
+{
+ struct Progress *pro = &data->progress;
+ struct PureInfo *info =&data->info;
+
+ pro->t_nslookup = 0;
+ pro->t_connect = 0;
+ pro->t_appconnect = 0;
+ pro->t_pretransfer = 0;
+ pro->t_starttransfer = 0;
+ pro->timespent = 0;
+ pro->t_redirect = 0;
+
+ 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);
+ info->contenttype = NULL;
+
+ info->header_size = 0;
+ info->request_size = 0;
+ info->numconnects = 0;
+
+ info->conn_primary_ip[0] = '\0';
+ info->conn_local_ip[0] = '\0';
+ info->conn_primary_port = 0;
+ info->conn_local_port = 0;
+
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_char(struct SessionHandle *data, CURLINFO info,
+ char **param_charp)
+{
+ switch(info) {
+ case CURLINFO_EFFECTIVE_URL:
+ *param_charp = data->change.url?data->change.url:(char *)"";
+ break;
+ case CURLINFO_CONTENT_TYPE:
+ *param_charp = data->info.contenttype;
+ break;
+ case CURLINFO_PRIVATE:
+ *param_charp = (char *) data->set.private_data;
+ break;
+ case CURLINFO_FTP_ENTRY_PATH:
+ /* Return the entrypath string from the most recent connection.
+ This pointer was copied from the connectdata structure by FTP.
+ The actual string may be free()ed by subsequent libcurl calls so
+ it must be copied to a safer area before the next libcurl call.
+ Callers must never free it themselves. */
+ *param_charp = data->state.most_recent_ftp_entrypath;
+ break;
+ case CURLINFO_REDIRECT_URL:
+ /* Return the URL this request would have been redirected to if that
+ option had been enabled! */
+ *param_charp = data->info.wouldredirect;
+ break;
+ case CURLINFO_PRIMARY_IP:
+ /* Return the ip address of the most recent (primary) connection */
+ *param_charp = data->info.conn_primary_ip;
+ break;
+ case CURLINFO_LOCAL_IP:
+ /* Return the source/local ip address of the most recent (primary)
+ connection */
+ *param_charp = data->info.conn_local_ip;
+ break;
+ case CURLINFO_RTSP_SESSION_ID:
+ *param_charp = data->set.str[STRING_RTSP_SESSION_ID];
+ break;
+
+ default:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_long(struct SessionHandle *data, CURLINFO info,
+ long *param_longp)
+{
+ curl_socket_t sockfd;
+
+ union {
+ unsigned long *to_ulong;
+ long *to_long;
+ } lptr;
+
+ switch(info) {
+ case CURLINFO_RESPONSE_CODE:
+ *param_longp = data->info.httpcode;
+ break;
+ case CURLINFO_HTTP_CONNECTCODE:
+ *param_longp = data->info.httpproxycode;
+ break;
+ case CURLINFO_FILETIME:
+ *param_longp = data->info.filetime;
+ break;
+ case CURLINFO_HEADER_SIZE:
+ *param_longp = data->info.header_size;
+ break;
+ case CURLINFO_REQUEST_SIZE:
+ *param_longp = data->info.request_size;
+ break;
+ case CURLINFO_SSL_VERIFYRESULT:
+ *param_longp = data->set.ssl.certverifyresult;
+ break;
+ case CURLINFO_REDIRECT_COUNT:
+ *param_longp = data->set.followlocation;
+ break;
+ case CURLINFO_HTTPAUTH_AVAIL:
+ lptr.to_long = param_longp;
+ *lptr.to_ulong = data->info.httpauthavail;
+ break;
+ case CURLINFO_PROXYAUTH_AVAIL:
+ lptr.to_long = param_longp;
+ *lptr.to_ulong = data->info.proxyauthavail;
+ break;
+ case CURLINFO_OS_ERRNO:
+ *param_longp = data->state.os_errno;
+ break;
+ case CURLINFO_NUM_CONNECTS:
+ *param_longp = data->info.numconnects;
+ break;
+ case CURLINFO_LASTSOCKET:
+ sockfd = Curl_getconnectinfo(data, NULL);
+
+ /* note: this is not a good conversion for systems with 64 bit sockets and
+ 32 bit longs */
+ if(sockfd != CURL_SOCKET_BAD)
+ *param_longp = (long)sockfd;
+ else
+ /* this interface is documented to return -1 in case of badness, which
+ may not be the same as the CURL_SOCKET_BAD value */
+ *param_longp = -1;
+ break;
+ case CURLINFO_PRIMARY_PORT:
+ /* Return the (remote) port of the most recent (primary) connection */
+ *param_longp = data->info.conn_primary_port;
+ break;
+ case CURLINFO_LOCAL_PORT:
+ /* Return the local port of the most recent (primary) connection */
+ *param_longp = data->info.conn_local_port;
+ break;
+ case CURLINFO_CONDITION_UNMET:
+ /* return if the condition prevented the document to get transferred */
+ *param_longp = data->info.timecond ? 1L : 0L;
+ break;
+ case CURLINFO_RTSP_CLIENT_CSEQ:
+ *param_longp = data->state.rtsp_next_client_CSeq;
+ break;
+ case CURLINFO_RTSP_SERVER_CSEQ:
+ *param_longp = data->state.rtsp_next_server_CSeq;
+ break;
+ case CURLINFO_RTSP_CSEQ_RECV:
+ *param_longp = data->state.rtsp_CSeq_recv;
+ break;
+
+ default:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_double(struct SessionHandle *data, CURLINFO info,
+ double *param_doublep)
+{
+ switch(info) {
+ case CURLINFO_TOTAL_TIME:
+ *param_doublep = data->progress.timespent;
+ break;
+ case CURLINFO_NAMELOOKUP_TIME:
+ *param_doublep = data->progress.t_nslookup;
+ break;
+ case CURLINFO_CONNECT_TIME:
+ *param_doublep = data->progress.t_connect;
+ break;
+ case CURLINFO_APPCONNECT_TIME:
+ *param_doublep = data->progress.t_appconnect;
+ break;
+ case CURLINFO_PRETRANSFER_TIME:
+ *param_doublep = data->progress.t_pretransfer;
+ break;
+ case CURLINFO_STARTTRANSFER_TIME:
+ *param_doublep = data->progress.t_starttransfer;
+ break;
+ case CURLINFO_SIZE_UPLOAD:
+ *param_doublep = (double)data->progress.uploaded;
+ break;
+ case CURLINFO_SIZE_DOWNLOAD:
+ *param_doublep = (double)data->progress.downloaded;
+ break;
+ case CURLINFO_SPEED_DOWNLOAD:
+ *param_doublep = (double)data->progress.dlspeed;
+ break;
+ case CURLINFO_SPEED_UPLOAD:
+ *param_doublep = (double)data->progress.ulspeed;
+ break;
+ case CURLINFO_CONTENT_LENGTH_DOWNLOAD:
+ *param_doublep = (data->progress.flags & PGRS_DL_SIZE_KNOWN)?
+ (double)data->progress.size_dl:-1;
+ break;
+ case CURLINFO_CONTENT_LENGTH_UPLOAD:
+ *param_doublep = (data->progress.flags & PGRS_UL_SIZE_KNOWN)?
+ (double)data->progress.size_ul:-1;
+ break;
+ case CURLINFO_REDIRECT_TIME:
+ *param_doublep = data->progress.t_redirect;
+ break;
+
+ default:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ return CURLE_OK;
+}
+
+static CURLcode getinfo_slist(struct SessionHandle *data, CURLINFO info,
+ struct curl_slist **param_slistp)
+{
+ union {
+ struct curl_certinfo * to_certinfo;
+ struct curl_slist * to_slist;
+ } ptr;
+
+ switch(info) {
+ case CURLINFO_SSL_ENGINES:
+ *param_slistp = Curl_ssl_engines_list(data);
+ break;
+ case CURLINFO_COOKIELIST:
+ *param_slistp = Curl_cookie_list(data);
+ break;
+ case CURLINFO_CERTINFO:
+ /* Return the a pointer to the certinfo struct. Not really an slist
+ pointer but we can pretend it is here */
+ ptr.to_certinfo = &data->info.certs;
+ *param_slistp = ptr.to_slist;
+ break;
+
+ default:
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ return CURLE_OK;
+}
+
+CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...)
+{
+ va_list arg;
+ long *param_longp=NULL;
+ double *param_doublep=NULL;
+ char **param_charp=NULL;
+ struct curl_slist **param_slistp=NULL;
+ int type;
+ /* default return code is to error out! */
+ CURLcode ret = CURLE_BAD_FUNCTION_ARGUMENT;
+
+ if(!data)
+ return ret;
+
+ va_start(arg, info);
+
+ type = CURLINFO_TYPEMASK & (int)info;
+ switch(type) {
+ case CURLINFO_STRING:
+ param_charp = va_arg(arg, char **);
+ if(NULL != param_charp)
+ ret = getinfo_char(data, info, param_charp);
+ break;
+ case CURLINFO_LONG:
+ param_longp = va_arg(arg, long *);
+ if(NULL != param_longp)
+ ret = getinfo_long(data, info, param_longp);
+ break;
+ case CURLINFO_DOUBLE:
+ param_doublep = va_arg(arg, double *);
+ if(NULL != param_doublep)
+ ret = getinfo_double(data, info, param_doublep);
+ break;
+ case CURLINFO_SLIST:
+ param_slistp = va_arg(arg, struct curl_slist **);
+ if(NULL != param_slistp)
+ ret = getinfo_slist(data, info, param_slistp);
+ break;
+ default:
+ break;
+ }
+
+ va_end(arg);
+ return ret;
+}
diff --git a/libs/libcurl/src/getinfo.h b/libs/libcurl/src/getinfo.h
new file mode 100644
index 0000000000..3879ff73a8
--- /dev/null
+++ b/libs/libcurl/src/getinfo.h
@@ -0,0 +1,27 @@
+#ifndef HEADER_CURL_GETINFO_H
+#define HEADER_CURL_GETINFO_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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.
+ *
+ ***************************************************************************/
+CURLcode Curl_getinfo(struct SessionHandle *data, CURLINFO info, ...);
+CURLcode Curl_initinfo(struct SessionHandle *data);
+
+#endif /* HEADER_CURL_GETINFO_H */
diff --git a/libs/libcurl/src/gopher.c b/libs/libcurl/src/gopher.c
new file mode 100644
index 0000000000..b1dd65fffe
--- /dev/null
+++ b/libs/libcurl/src/gopher.c
@@ -0,0 +1,169 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#ifndef CURL_DISABLE_GOPHER
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+
+#include "progress.h"
+#include "strequal.h"
+#include "gopher.h"
+#include "rawstr.h"
+#include "select.h"
+#include "url.h"
+#include "warnless.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"
+
+/*
+ * Forward declarations.
+ */
+
+static CURLcode gopher_do(struct connectdata *conn, bool *done);
+
+/*
+ * Gopher protocol handler.
+ * This is also a nice simple template to build off for simple
+ * connect-command-download protocols.
+ */
+
+const struct Curl_handler Curl_handler_gopher = {
+ "GOPHER", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ gopher_do, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_GOPHER, /* defport */
+ CURLPROTO_GOPHER, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+static CURLcode gopher_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result=CURLE_OK;
+ struct SessionHandle *data=conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+
+ curl_off_t *bytecount = &data->req.bytecount;
+ char *path = data->state.path;
+ char *sel;
+ char *sel_org = NULL;
+ ssize_t amount, k;
+
+ *done = TRUE; /* unconditionally */
+
+ /* Create selector. Degenerate cases: / and /1 => convert to "" */
+ if(strlen(path) <= 2)
+ sel = (char *)"";
+ else {
+ char *newp;
+ size_t j, i;
+ int len;
+
+ /* Otherwise, drop / and the first character (i.e., item type) ... */
+ newp = path;
+ newp+=2;
+
+ /* ... then turn ? into TAB for search servers, Veronica, etc. ... */
+ j = strlen(newp);
+ for(i=0; i<j; i++)
+ if(newp[i] == '?')
+ newp[i] = '\x09';
+
+ /* ... and finally unescape */
+ sel = curl_easy_unescape(data, newp, 0, &len);
+ if(!sel)
+ return CURLE_OUT_OF_MEMORY;
+ sel_org = sel;
+ }
+
+ /* We use Curl_write instead of Curl_sendf to make sure the entire buffer is
+ sent, which could be sizeable with long selectors. */
+ k = curlx_uztosz(strlen(sel));
+
+ for(;;) {
+ result = Curl_write(conn, sockfd, sel, k, &amount);
+ if(CURLE_OK == result) { /* Which may not have written it all! */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, sel, amount);
+ if(result) {
+ Curl_safefree(sel_org);
+ return result;
+ }
+ k -= amount;
+ sel += amount;
+ if(k < 1)
+ break; /* but it did write it all */
+ }
+ else {
+ failf(data, "Failed sending Gopher request");
+ Curl_safefree(sel_org);
+ return result;
+ }
+ /* Don't busyloop. The entire loop thing is a work-around as it causes a
+ BLOCKING behavior which is a NO-NO. This function should rather be
+ split up in a do and a doing piece where the pieces that aren't
+ possible to send now will be sent in the doing function repeatedly
+ until the entire request is sent.
+
+ Wait a while for the socket to be writable. Note that this doesn't
+ acknowledge the timeout.
+ */
+ Curl_socket_ready(CURL_SOCKET_BAD, sockfd, 100);
+ }
+
+ Curl_safefree(sel_org);
+
+ /* We can use Curl_sendf to send the terminal \r\n relatively safely and
+ save allocing another string/doing another _write loop. */
+ result = Curl_sendf(sockfd, conn, "\r\n");
+ if(result != CURLE_OK) {
+ failf(data, "Failed sending Gopher request");
+ return result;
+ }
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, (char *)"\r\n", 2);
+ if(result)
+ return result;
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, bytecount,
+ -1, NULL); /* no upload */
+ return CURLE_OK;
+}
+#endif /*CURL_DISABLE_GOPHER*/
diff --git a/libs/libcurl/src/gopher.h b/libs/libcurl/src/gopher.h
new file mode 100644
index 0000000000..38bbc4b738
--- /dev/null
+++ b/libs/libcurl/src/gopher.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_GOPHER_H
+#define HEADER_CURL_GOPHER_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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.
+ *
+ ***************************************************************************/
+
+#ifndef CURL_DISABLE_GOPHER
+extern const struct Curl_handler Curl_handler_gopher;
+#endif
+
+#endif /* HEADER_CURL_GOPHER_H */
diff --git a/libs/libcurl/src/gskit.c b/libs/libcurl/src/gskit.c
new file mode 100644
index 0000000000..5cda85b9b8
--- /dev/null
+++ b/libs/libcurl/src/gskit.c
@@ -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 */
diff --git a/libs/libcurl/src/gskit.h b/libs/libcurl/src/gskit.h
new file mode 100644
index 0000000000..0d59aa7096
--- /dev/null
+++ b/libs/libcurl/src/gskit.h
@@ -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 */
diff --git a/libs/libcurl/src/gtls.c b/libs/libcurl/src/gtls.c
new file mode 100644
index 0000000000..700e46a9da
--- /dev/null
+++ b/libs/libcurl/src/gtls.c
@@ -0,0 +1,1119 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all GnuTLS-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ * Note: don't use the GnuTLS' *_t variable type names in this source code,
+ * since they were not present in 1.0.X.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_GNUTLS
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#ifdef USE_GNUTLS_NETTLE
+#include <gnutls/crypto.h>
+#include <nettle/md5.h>
+#else
+#include <gcrypt.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "gtls.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.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"
+
+/*
+ Some hackish cast macros based on:
+ http://library.gnome.org/devel/glib/unstable/glib-Type-Conversion-Macros.html
+*/
+#ifndef GNUTLS_POINTER_TO_INT_CAST
+#define GNUTLS_POINTER_TO_INT_CAST(p) ((int) (long) (p))
+#endif
+#ifndef GNUTLS_INT_TO_POINTER_CAST
+#define GNUTLS_INT_TO_POINTER_CAST(i) ((void*) (long) (i))
+#endif
+
+/* Enable GnuTLS debugging by defining GTLSDEBUG */
+/*#define GTLSDEBUG */
+
+#ifdef GTLSDEBUG
+static void tls_log_func(int level, const char *str)
+{
+ fprintf(stderr, "|<%d>| %s", level, str);
+}
+#endif
+static bool gtls_inited = FALSE;
+
+#if defined(GNUTLS_VERSION_NUMBER)
+# if (GNUTLS_VERSION_NUMBER >= 0x020c00)
+# undef gnutls_transport_set_lowat
+# define gnutls_transport_set_lowat(A,B) Curl_nop_stmt
+# define USE_GNUTLS_PRIORITY_SET_DIRECT 1
+# endif
+# if (GNUTLS_VERSION_NUMBER >= 0x020c03)
+# define GNUTLS_MAPS_WINSOCK_ERRORS 1
+# endif
+#endif
+
+/*
+ * Custom push and pull callback functions used by GNU TLS to read and write
+ * to the socket. These functions are simple wrappers to send() and recv()
+ * (although here using the sread/swrite macros as defined by
+ * curl_setup_once.h).
+ * We use custom functions rather than the GNU TLS defaults because it allows
+ * us to get specific about the fourth "flags" argument, and to use arbitrary
+ * private data with gnutls_transport_set_ptr if we wish.
+ *
+ * When these custom push and pull callbacks fail, GNU TLS checks its own
+ * session-specific error variable, and when not set also its own global
+ * errno variable, in order to take appropriate action. GNU TLS does not
+ * require that the transport is actually a socket. This implies that for
+ * Windows builds these callbacks should ideally set the session-specific
+ * error variable using function gnutls_transport_set_errno or as a last
+ * resort global errno variable using gnutls_transport_set_global_errno,
+ * with a transport agnostic error value. This implies that some winsock
+ * error translation must take place in these callbacks.
+ *
+ * Paragraph above applies to GNU TLS versions older than 2.12.3, since
+ * this version GNU TLS does its own internal winsock error translation
+ * using system_errno() function.
+ */
+
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+# define gtls_EINTR 4
+# define gtls_EIO 5
+# define gtls_EAGAIN 11
+static int gtls_mapped_sockerrno(void)
+{
+ switch(SOCKERRNO) {
+ case WSAEWOULDBLOCK:
+ return gtls_EAGAIN;
+ case WSAEINTR:
+ return gtls_EINTR;
+ default:
+ break;
+ }
+ return gtls_EIO;
+}
+#endif
+
+static ssize_t Curl_gtls_push(void *s, const void *buf, size_t len)
+{
+ ssize_t ret = swrite(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+ if(ret < 0)
+ gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
+#endif
+ return ret;
+}
+
+static ssize_t Curl_gtls_pull(void *s, void *buf, size_t len)
+{
+ ssize_t ret = sread(GNUTLS_POINTER_TO_INT_CAST(s), buf, len);
+#if defined(USE_WINSOCK) && !defined(GNUTLS_MAPS_WINSOCK_ERRORS)
+ if(ret < 0)
+ gnutls_transport_set_global_errno(gtls_mapped_sockerrno());
+#endif
+ return ret;
+}
+
+/* Curl_gtls_init()
+ *
+ * Global GnuTLS init, called from Curl_ssl_init(). This calls functions that
+ * are not thread-safe and thus this function itself is not thread-safe and
+ * must only be called from within curl_global_init() to keep the thread
+ * situation under control!
+ */
+int Curl_gtls_init(void)
+{
+ int ret = 1;
+ if(!gtls_inited) {
+ ret = gnutls_global_init()?0:1;
+#ifdef GTLSDEBUG
+ gnutls_global_set_log_function(tls_log_func);
+ gnutls_global_set_log_level(2);
+#endif
+ gtls_inited = TRUE;
+ }
+ return ret;
+}
+
+int Curl_gtls_cleanup(void)
+{
+ if(gtls_inited) {
+ gnutls_global_deinit();
+ gtls_inited = FALSE;
+ }
+ return 1;
+}
+
+static void showtime(struct SessionHandle *data,
+ const char *text,
+ time_t stamp)
+{
+ struct tm buffer;
+ const struct tm *tm = &buffer;
+ CURLcode result = Curl_gmtime(stamp, &buffer);
+ if(result)
+ return;
+
+ snprintf(data->state.buffer,
+ BUFSIZE,
+ "\t %s: %s, %02d %s %4d %02d:%02d:%02d GMT\n",
+ text,
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+ infof(data, "%s\n", data->state.buffer);
+}
+
+static gnutls_datum load_file (const char *file)
+{
+ FILE *f;
+ gnutls_datum loaded_file = { NULL, 0 };
+ long filelen;
+ void *ptr;
+
+ if(!(f = fopen(file, "r")))
+ return loaded_file;
+ if(fseek(f, 0, SEEK_END) != 0
+ || (filelen = ftell(f)) < 0
+ || fseek(f, 0, SEEK_SET) != 0
+ || !(ptr = malloc((size_t)filelen)))
+ goto out;
+ if(fread(ptr, 1, (size_t)filelen, f) < (size_t)filelen) {
+ free(ptr);
+ goto out;
+ }
+
+ loaded_file.data = ptr;
+ loaded_file.size = (unsigned int)filelen;
+out:
+ fclose(f);
+ return loaded_file;
+}
+
+static void unload_file(gnutls_datum data) {
+ free(data.data);
+}
+
+
+/* this function does a SSL/TLS (re-)handshake */
+static CURLcode handshake(struct connectdata *conn,
+ int sockindex,
+ bool duringconnect,
+ bool nonblocking)
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ gnutls_session session = conn->ssl[sockindex].session;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int rc;
+ int what;
+
+ for(;;) {
+ /* check allowed time left */
+ timeout_ms = Curl_timeleft(data, NULL, duringconnect);
+
+ if(timeout_ms < 0) {
+ /* no need to continue if time already is up */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd,
+ nonblocking?0:
+ timeout_ms?timeout_ms:1000);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking)
+ return CURLE_OK;
+ else if(timeout_ms) {
+ /* timeout */
+ failf(data, "SSL connection timeout at %ld", timeout_ms);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ rc = gnutls_handshake(session);
+
+ if((rc == GNUTLS_E_AGAIN) || (rc == GNUTLS_E_INTERRUPTED)) {
+ connssl->connecting_state =
+ gnutls_record_get_direction(session)?
+ ssl_connect_2_writing:ssl_connect_2_reading;
+ continue;
+ if(nonblocking)
+ return CURLE_OK;
+ }
+ else if((rc < 0) && !gnutls_error_is_fatal(rc)) {
+ const char *strerr = NULL;
+
+ if(rc == GNUTLS_E_WARNING_ALERT_RECEIVED) {
+ int alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
+ }
+
+ if(strerr == NULL)
+ strerr = gnutls_strerror(rc);
+
+ failf(data, "gnutls_handshake() warning: %s", strerr);
+ }
+ else if(rc < 0) {
+ const char *strerr = NULL;
+
+ if(rc == GNUTLS_E_FATAL_ALERT_RECEIVED) {
+ int alert = gnutls_alert_get(session);
+ strerr = gnutls_alert_get_name(alert);
+ }
+
+ if(strerr == NULL)
+ strerr = gnutls_strerror(rc);
+
+ failf(data, "gnutls_handshake() failed: %s", strerr);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+ return CURLE_OK;
+ }
+}
+
+static gnutls_x509_crt_fmt do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return GNUTLS_X509_FMT_PEM;
+ if(Curl_raw_equal(type, "PEM"))
+ return GNUTLS_X509_FMT_PEM;
+ if(Curl_raw_equal(type, "DER"))
+ return GNUTLS_X509_FMT_DER;
+ return -1;
+}
+
+static CURLcode
+gtls_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+ static const int cert_type_priority[] = { GNUTLS_CRT_X509, 0 };
+#endif
+ struct SessionHandle *data = conn->data;
+ gnutls_session session;
+ int rc;
+ void *ssl_sessionid;
+ size_t ssl_idsize;
+ bool sni = TRUE; /* default is SNI enabled */
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+
+ if(conn->ssl[sockindex].state == ssl_connection_complete)
+ /* to make us tolerant against being called more than once for the
+ same connection */
+ return CURLE_OK;
+
+ if(!gtls_inited)
+ Curl_gtls_init();
+
+ /* GnuTLS only supports SSLv3 and TLSv1 */
+ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "GnuTLS does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+ /* allocate a cred struct */
+ rc = gnutls_certificate_allocate_credentials(&conn->ssl[sockindex].cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_cert_all_cred() failed: %s", gnutls_strerror(rc));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
+
+ rc = gnutls_srp_allocate_client_credentials(
+ &conn->ssl[sockindex].srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_allocate_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ rc = gnutls_srp_set_client_credentials(conn->ssl[sockindex].
+ srp_client_cred,
+ data->set.ssl.username,
+ data->set.ssl.password);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_srp_set_client_cred() failed: %s",
+ gnutls_strerror(rc));
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ }
+#endif
+
+ if(data->set.ssl.CAfile) {
+ /* set the trusted CA cert bundle file */
+ gnutls_certificate_set_verify_flags(conn->ssl[sockindex].cred,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);
+
+ rc = gnutls_certificate_set_x509_trust_file(conn->ssl[sockindex].cred,
+ data->set.ssl.CAfile,
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ infof(data, "error reading ca cert file %s (%s)\n",
+ data->set.ssl.CAfile, gnutls_strerror(rc));
+ if(data->set.ssl.verifypeer)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else
+ infof(data, "found %d certificates in %s\n",
+ rc, data->set.ssl.CAfile);
+ }
+
+ if(data->set.ssl.CRLfile) {
+ /* set the CRL list file */
+ rc = gnutls_certificate_set_x509_crl_file(conn->ssl[sockindex].cred,
+ data->set.ssl.CRLfile,
+ GNUTLS_X509_FMT_PEM);
+ if(rc < 0) {
+ failf(data, "error reading crl file %s (%s)",
+ data->set.ssl.CRLfile, gnutls_strerror(rc));
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ else
+ infof(data, "found %d CRL in %s\n",
+ rc, data->set.ssl.CRLfile);
+ }
+
+ /* Initialize TLS session as a client */
+ rc = gnutls_init(&conn->ssl[sockindex].session, GNUTLS_CLIENT);
+ if(rc != GNUTLS_E_SUCCESS) {
+ failf(data, "gnutls_init() failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* convenient assign */
+ session = conn->ssl[sockindex].session;
+
+ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+#endif
+ sni &&
+ (gnutls_server_name_set(session, GNUTLS_NAME_DNS, conn->host.name,
+ strlen(conn->host.name)) < 0))
+ infof(data, "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+
+ /* Use default priorities */
+ rc = gnutls_set_default_priority(session);
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+
+ if(data->set.ssl.version == CURL_SSLVERSION_SSLv3) {
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+ static const int protocol_priority[] = { GNUTLS_SSL3, 0 };
+ rc = gnutls_protocol_set_priority(session, protocol_priority);
+#else
+ const char *err;
+ /* the combination of the cipher ARCFOUR with SSL 3.0 and TLS 1.0 is not
+ vulnerable to attacks such as the BEAST, why this code now explicitly
+ asks for that
+ */
+ rc = gnutls_priority_set_direct(session,
+ "NORMAL:-VERS-TLS-ALL:+VERS-SSL3.0:"
+ "-CIPHER-ALL:+ARCFOUR-128",
+ &err);
+#endif
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+#ifndef USE_GNUTLS_PRIORITY_SET_DIRECT
+ /* Sets the priority on the certificate types supported by gnutls. Priority
+ is higher for types specified before others. After specifying the types
+ you want, you must append a 0. */
+ rc = gnutls_certificate_type_set_priority(session, cert_type_priority);
+ if(rc != GNUTLS_E_SUCCESS)
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+
+ if(data->set.str[STRING_CERT]) {
+ if(gnutls_certificate_set_x509_key_file(
+ conn->ssl[sockindex].cred,
+ data->set.str[STRING_CERT],
+ data->set.str[STRING_KEY] ?
+ data->set.str[STRING_KEY] : data->set.str[STRING_CERT],
+ do_file_type(data->set.str[STRING_CERT_TYPE]) ) !=
+ GNUTLS_E_SUCCESS) {
+ failf(data, "error reading X.509 key or certificate file");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ }
+
+#ifdef USE_TLS_SRP
+ /* put the credentials to the current session */
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ rc = gnutls_credentials_set(session, GNUTLS_CRD_SRP,
+ conn->ssl[sockindex].srp_client_cred);
+ if(rc != GNUTLS_E_SUCCESS)
+ failf(data, "gnutls_credentials_set() failed: %s", gnutls_strerror(rc));
+ }
+ else
+#endif
+ rc = gnutls_credentials_set(session, GNUTLS_CRD_CERTIFICATE,
+ conn->ssl[sockindex].cred);
+
+ /* set the connection handle (file descriptor for the socket) */
+ gnutls_transport_set_ptr(session,
+ GNUTLS_INT_TO_POINTER_CAST(conn->sock[sockindex]));
+
+ /* register callback functions to send and receive data. */
+ gnutls_transport_set_push_function(session, Curl_gtls_push);
+ gnutls_transport_set_pull_function(session, Curl_gtls_pull);
+
+ /* lowat must be set to zero when using custom push and pull functions. */
+ gnutls_transport_set_lowat(session, 0);
+
+ /* This might be a reconnect, so we check for a session ID in the cache
+ to speed up things */
+
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, &ssl_idsize)) {
+ /* we got a session id, use it! */
+ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+
+ /* Informational message */
+ infof (data, "SSL re-using session ID\n");
+ }
+
+ return CURLE_OK;
+}
+
+static Curl_recv gtls_recv;
+static Curl_send gtls_send;
+
+static CURLcode
+gtls_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ unsigned int cert_list_size;
+ const gnutls_datum *chainp;
+ unsigned int verify_status;
+ gnutls_x509_crt x509_cert,x509_issuer;
+ gnutls_datum issuerp;
+ char certbuf[256]; /* big enough? */
+ size_t size;
+ unsigned int algo;
+ unsigned int bits;
+ time_t certclock;
+ const char *ptr;
+ struct SessionHandle *data = conn->data;
+ gnutls_session session = conn->ssl[sockindex].session;
+ int rc;
+ int incache;
+ void *ssl_sessionid;
+ CURLcode result = CURLE_OK;
+
+ /* This function will return the peer's raw certificate (chain) as sent by
+ the peer. These certificates are in raw format (DER encoded for
+ X.509). In case of a X.509 then a certificate list may be present. The
+ first certificate in the list is the peer's certificate, following the
+ issuer's certificate, then the issuer's issuer etc. */
+
+ chainp = gnutls_certificate_get_peers(session, &cert_list_size);
+ if(!chainp) {
+ if(data->set.ssl.verifypeer ||
+ data->set.ssl.verifyhost ||
+ data->set.ssl.issuercert) {
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
+ && data->set.ssl.username != NULL
+ && !data->set.ssl.verifypeer
+ && gnutls_cipher_get(session)) {
+ /* no peer cert, but auth is ok if we have SRP user and cipher and no
+ peer verify */
+ }
+ else {
+#endif
+ failf(data, "failed to get server cert");
+ return CURLE_PEER_FAILED_VERIFICATION;
+#ifdef USE_TLS_SRP
+ }
+#endif
+ }
+ infof(data, "\t common name: WARNING couldn't obtain\n");
+ }
+
+ if(data->set.ssl.verifypeer) {
+ /* This function will try to verify the peer's certificate and return its
+ status (trusted, invalid etc.). The value of status should be one or
+ more of the gnutls_certificate_status_t enumerated elements bitwise
+ or'd. To avoid denial of service attacks some default upper limits
+ regarding the certificate key size and chain size are set. To override
+ them use gnutls_certificate_set_verify_limits(). */
+
+ rc = gnutls_certificate_verify_peers2(session, &verify_status);
+ if(rc < 0) {
+ failf(data, "server cert verify failed: %d", rc);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* verify_status is a bitmask of gnutls_certificate_status bits */
+ if(verify_status & GNUTLS_CERT_INVALID) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate verification failed. CAfile: %s "
+ "CRLfile: %s", data->set.ssl.CAfile?data->set.ssl.CAfile:"none",
+ data->set.ssl.CRLfile?data->set.ssl.CRLfile:"none");
+ return CURLE_SSL_CACERT;
+ }
+ else
+ infof(data, "\t server certificate verification FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate verification OK\n");
+ }
+ else {
+ infof(data, "\t server certificate verification SKIPPED\n");
+ goto after_server_cert_verification;
+ }
+
+ /* initialize an X.509 certificate structure. */
+ gnutls_x509_crt_init(&x509_cert);
+
+ /* convert the given DER or PEM encoded Certificate to the native
+ gnutls_x509_crt_t format */
+ gnutls_x509_crt_import(x509_cert, chainp, GNUTLS_X509_FMT_DER);
+
+ if(data->set.ssl.issuercert) {
+ gnutls_x509_crt_init(&x509_issuer);
+ issuerp = load_file(data->set.ssl.issuercert);
+ gnutls_x509_crt_import(x509_issuer, &issuerp, GNUTLS_X509_FMT_PEM);
+ rc = gnutls_x509_crt_check_issuer(x509_cert,x509_issuer);
+ unload_file(issuerp);
+ if(rc <= 0) {
+ failf(data, "server certificate issuer check failed (IssuerCert: %s)",
+ data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+ infof(data,"\t server certificate issuer check OK (Issuer Cert: %s)\n",
+ data->set.ssl.issuercert?data->set.ssl.issuercert:"none");
+ }
+
+ size=sizeof(certbuf);
+ rc = gnutls_x509_crt_get_dn_by_oid(x509_cert, GNUTLS_OID_X520_COMMON_NAME,
+ 0, /* the first and only one */
+ FALSE,
+ certbuf,
+ &size);
+ if(rc) {
+ infof(data, "error fetching CN from cert:%s\n",
+ gnutls_strerror(rc));
+ }
+
+ /* This function will check if the given certificate's subject matches the
+ given hostname. This is a basic implementation of the matching described
+ in RFC2818 (HTTPS), which takes into account wildcards, and the subject
+ alternative name PKIX extension. Returns non zero on success, and zero on
+ failure. */
+ rc = gnutls_x509_crt_check_hostname(x509_cert, conn->host.name);
+
+ if(!rc) {
+ if(data->set.ssl.verifyhost) {
+ failf(data, "SSL: certificate subject name (%s) does not match "
+ "target host name '%s'", certbuf, conn->host.dispname);
+ gnutls_x509_crt_deinit(x509_cert);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t common name: %s (does not match '%s')\n",
+ certbuf, conn->host.dispname);
+ }
+ else
+ infof(data, "\t common name: %s (matched)\n", certbuf);
+
+ /* Check for time-based validity */
+ certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+
+ if(certclock == (time_t)-1) {
+ failf(data, "server cert expiration date verify failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(certclock < time(NULL)) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate expiration date has passed.");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate expiration date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate expiration date OK\n");
+
+ certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+
+ if(certclock == (time_t)-1) {
+ failf(data, "server cert activation date verify failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ if(certclock > time(NULL)) {
+ if(data->set.ssl.verifypeer) {
+ failf(data, "server certificate not activated yet.");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t server certificate activation date FAILED\n");
+ }
+ else
+ infof(data, "\t server certificate activation date OK\n");
+
+ /* Show:
+
+ - ciphers used
+ - subject
+ - start date
+ - expire date
+ - common name
+ - issuer
+
+ */
+
+ /* public key algorithm's parameters */
+ algo = gnutls_x509_crt_get_pk_algorithm(x509_cert, &bits);
+ infof(data, "\t certificate public key: %s\n",
+ gnutls_pk_algorithm_get_name(algo));
+
+ /* version of the X.509 certificate. */
+ infof(data, "\t certificate version: #%d\n",
+ gnutls_x509_crt_get_version(x509_cert));
+
+
+ size = sizeof(certbuf);
+ gnutls_x509_crt_get_dn(x509_cert, certbuf, &size);
+ infof(data, "\t subject: %s\n", certbuf);
+
+ certclock = gnutls_x509_crt_get_activation_time(x509_cert);
+ showtime(data, "start date", certclock);
+
+ certclock = gnutls_x509_crt_get_expiration_time(x509_cert);
+ showtime(data, "expire date", certclock);
+
+ size = sizeof(certbuf);
+ gnutls_x509_crt_get_issuer_dn(x509_cert, certbuf, &size);
+ infof(data, "\t issuer: %s\n", certbuf);
+
+ gnutls_x509_crt_deinit(x509_cert);
+
+after_server_cert_verification:
+
+ /* compression algorithm (if any) */
+ ptr = gnutls_compression_get_name(gnutls_compression_get(session));
+ /* the *_get_name() says "NULL" if GNUTLS_COMP_NULL is returned */
+ infof(data, "\t compression: %s\n", ptr);
+
+ /* the name of the cipher used. ie 3DES. */
+ ptr = gnutls_cipher_get_name(gnutls_cipher_get(session));
+ infof(data, "\t cipher: %s\n", ptr);
+
+ /* the MAC algorithms name. ie SHA1 */
+ ptr = gnutls_mac_get_name(gnutls_mac_get(session));
+ infof(data, "\t MAC: %s\n", ptr);
+
+ conn->ssl[sockindex].state = ssl_connection_complete;
+ conn->recv[sockindex] = gtls_recv;
+ conn->send[sockindex] = gtls_send;
+
+ {
+ /* we always unconditionally get the session id here, as even if we
+ already got it from the cache and asked to use it in the connection, it
+ might've been rejected and then a new one is in use now and we need to
+ detect that. */
+ void *connect_sessionid;
+ size_t connect_idsize;
+
+ /* get the session ID data size */
+ gnutls_session_get_data(session, NULL, &connect_idsize);
+ connect_sessionid = malloc(connect_idsize); /* get a buffer for it */
+
+ if(connect_sessionid) {
+ /* extract session ID to the allocated buffer */
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ incache = !(Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+ Curl_ssl_delsessionid(conn, ssl_sessionid);
+ }
+
+ /* store this session id */
+ result = Curl_ssl_addsessionid(conn, connect_sessionid, connect_idsize);
+ if(result) {
+ free(connect_sessionid);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ else
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+
+/*
+ * This function is called after the TCP connect has completed. Setup the TLS
+ * layer and do all necessary magic.
+ */
+/* We use connssl->connecting_state to keep track of the connection status;
+ there are three states: 'ssl_connect_1' (not started yet or complete),
+ 'ssl_connect_2_reading' (waiting for data from server), and
+ 'ssl_connect_2_writing' (waiting to be able to write).
+ */
+static CURLcode
+gtls_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ int rc;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ /* Initiate the connection, if not already done */
+ if(ssl_connect_1==connssl->connecting_state) {
+ rc = gtls_connect_step1 (conn, sockindex);
+ if(rc)
+ return rc;
+ }
+
+ rc = handshake(conn, sockindex, TRUE, nonblocking);
+ if(rc)
+ /* handshake() sets its own error message with failf() */
+ return rc;
+
+ /* Finish connecting once the handshake is done */
+ if(ssl_connect_1==connssl->connecting_state) {
+ rc = gtls_connect_step3(conn, sockindex);
+ if(rc)
+ return rc;
+ }
+
+ *done = ssl_connect_1==connssl->connecting_state;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_gtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return gtls_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_gtls_connect(struct connectdata *conn,
+ int sockindex)
+
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = gtls_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+static ssize_t gtls_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ ssize_t rc = gnutls_record_send(conn->ssl[sockindex].session, mem, len);
+
+ if(rc < 0 ) {
+ *curlcode = (rc == GNUTLS_E_AGAIN)
+ ? CURLE_AGAIN
+ : CURLE_SEND_ERROR;
+
+ rc = -1;
+ }
+
+ return rc;
+}
+
+void Curl_gtls_close_all(struct SessionHandle *data)
+{
+ /* FIX: make the OpenSSL code more generic and use parts of it here */
+ (void)data;
+}
+
+static void close_one(struct connectdata *conn,
+ int idx)
+{
+ if(conn->ssl[idx].session) {
+ gnutls_bye(conn->ssl[idx].session, GNUTLS_SHUT_RDWR);
+ gnutls_deinit(conn->ssl[idx].session);
+ conn->ssl[idx].session = NULL;
+ }
+ if(conn->ssl[idx].cred) {
+ gnutls_certificate_free_credentials(conn->ssl[idx].cred);
+ conn->ssl[idx].cred = NULL;
+ }
+#ifdef USE_TLS_SRP
+ if(conn->ssl[idx].srp_client_cred) {
+ gnutls_srp_free_client_credentials(conn->ssl[idx].srp_client_cred);
+ conn->ssl[idx].srp_client_cred = NULL;
+ }
+#endif
+}
+
+void Curl_gtls_close(struct connectdata *conn, int sockindex)
+{
+ close_one(conn, sockindex);
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex)
+{
+ ssize_t result;
+ int retval = 0;
+ struct SessionHandle *data = conn->data;
+ int done = 0;
+ char buf[120];
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ gnutls_bye(conn->ssl[sockindex].session, GNUTLS_SHUT_WR);
+
+ if(conn->ssl[sockindex].session) {
+ while(!done) {
+ int what = Curl_socket_ready(conn->sock[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 */
+ result = gnutls_record_recv(conn->ssl[sockindex].session,
+ buf, sizeof(buf));
+ switch(result) {
+ case 0:
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = 1;
+ break;
+ case GNUTLS_E_AGAIN:
+ case GNUTLS_E_INTERRUPTED:
+ infof(data, "GNUTLS_E_AGAIN || GNUTLS_E_INTERRUPTED\n");
+ break;
+ default:
+ retval = -1;
+ done = 1;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = 1;
+ break;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = 1;
+ }
+ }
+ gnutls_deinit(conn->ssl[sockindex].session);
+ }
+ gnutls_certificate_free_credentials(conn->ssl[sockindex].cred);
+
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP
+ && data->set.ssl.username != NULL)
+ gnutls_srp_free_client_credentials(conn->ssl[sockindex].srp_client_cred);
+#endif
+
+ conn->ssl[sockindex].cred = NULL;
+ conn->ssl[sockindex].session = NULL;
+
+ return retval;
+}
+
+static ssize_t gtls_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ ssize_t ret;
+
+ ret = gnutls_record_recv(conn->ssl[num].session, buf, buffersize);
+ if((ret == GNUTLS_E_AGAIN) || (ret == GNUTLS_E_INTERRUPTED)) {
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
+
+ if(ret == GNUTLS_E_REHANDSHAKE) {
+ /* BLOCKING call, this is bad but a work-around for now. Fixing this "the
+ proper way" takes a whole lot of work. */
+ CURLcode rc = handshake(conn, num, FALSE, FALSE);
+ if(rc)
+ /* handshake() writes error message on its own */
+ *curlcode = rc;
+ else
+ *curlcode = CURLE_AGAIN; /* then return as if this was a wouldblock */
+ return -1;
+ }
+
+ if(ret < 0) {
+ failf(conn->data, "GnuTLS recv error (%d): %s",
+ (int)ret, gnutls_strerror((int)ret));
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ return ret;
+}
+
+void Curl_gtls_session_free(void *ptr)
+{
+ free(ptr);
+}
+
+size_t Curl_gtls_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "GnuTLS/%s", gnutls_check_version(NULL));
+}
+
+int Curl_gtls_seed(struct SessionHandle *data)
+{
+ /* we have the "SSL is seeded" boolean static to prevent multiple
+ time-consuming seedings in vain */
+ static bool ssl_seeded = FALSE;
+
+ /* Quickly add a bit of entropy */
+#ifndef USE_GNUTLS_NETTLE
+ gcry_fast_random_poll();
+#endif
+
+ if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+ data->set.str[STRING_SSL_EGDSOCKET]) {
+
+ /* TODO: to a good job seeding the RNG
+ This may involve the gcry_control function and these options:
+ GCRYCTL_SET_RANDOM_SEED_FILE
+ GCRYCTL_SET_RNDEGD_SOCKET
+ */
+ ssl_seeded = TRUE;
+ }
+ return 0;
+}
+
+void Curl_gtls_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length)
+{
+#if defined(USE_GNUTLS_NETTLE)
+ (void)data;
+ gnutls_rnd(GNUTLS_RND_RANDOM, entropy, length);
+#elif defined(USE_GNUTLS)
+ Curl_gtls_seed(data); /* Initiate the seed if not already done */
+ gcry_randomize(entropy, length, GCRY_STRONG_RANDOM);
+#endif
+}
+
+void Curl_gtls_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+#if defined(USE_GNUTLS_NETTLE)
+ struct md5_ctx MD5pw;
+ md5_init(&MD5pw);
+ md5_update(&MD5pw, tmplen, tmp);
+ md5_digest(&MD5pw, md5len, md5sum);
+#elif defined(USE_GNUTLS)
+ gcry_md_hd_t MD5pw;
+ gcry_md_open(&MD5pw, GCRY_MD_MD5, 0);
+ gcry_md_write(MD5pw, tmp, tmplen);
+ memcpy(md5sum, gcry_md_read (MD5pw, 0), md5len);
+ gcry_md_close(MD5pw);
+#endif
+}
+
+#endif /* USE_GNUTLS */
diff --git a/libs/libcurl/src/gtls.h b/libs/libcurl/src/gtls.h
new file mode 100644
index 0000000000..453542e1ec
--- /dev/null
+++ b/libs/libcurl/src/gtls.h
@@ -0,0 +1,81 @@
+#ifndef HEADER_CURL_GTLS_H
+#define HEADER_CURL_GTLS_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"
+
+#ifdef USE_GNUTLS
+
+#include "urldata.h"
+
+int Curl_gtls_init(void);
+int Curl_gtls_cleanup(void);
+CURLcode Curl_gtls_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_gtls_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* tell GnuTLS to close down all open information regarding connections (and
+ thus session ID caching etc) */
+void Curl_gtls_close_all(struct SessionHandle *data);
+
+ /* close a SSL connection */
+void Curl_gtls_close(struct connectdata *conn, int sockindex);
+
+void Curl_gtls_session_free(void *ptr);
+size_t Curl_gtls_version(char *buffer, size_t size);
+int Curl_gtls_shutdown(struct connectdata *conn, int sockindex);
+int Curl_gtls_seed(struct SessionHandle *data);
+
+void Curl_gtls_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length);
+void Curl_gtls_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ 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
+#define curlssl_connect Curl_gtls_connect
+#define curlssl_connect_nonblocking Curl_gtls_connect_nonblocking
+#define curlssl_session_free(x) Curl_gtls_session_free(x)
+#define curlssl_close_all Curl_gtls_close_all
+#define curlssl_close Curl_gtls_close
+#define curlssl_shutdown(x,y) Curl_gtls_shutdown(x,y)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_gtls_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+#define curlssl_random(x,y,z) Curl_gtls_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_gtls_md5sum(a,b,c,d)
+
+#endif /* USE_GNUTLS */
+#endif /* HEADER_CURL_GTLS_H */
diff --git a/libs/libcurl/src/hash.c b/libs/libcurl/src/hash.c
new file mode 100644
index 0000000000..4a12e1a7b9
--- /dev/null
+++ b/libs/libcurl/src/hash.c
@@ -0,0 +1,400 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "hash.h"
+#include "llist.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"
+
+static void
+hash_element_dtor(void *user, void *element)
+{
+ struct curl_hash *h = (struct curl_hash *) user;
+ struct curl_hash_element *e = (struct curl_hash_element *) element;
+
+ Curl_safefree(e->key);
+
+ if(e->ptr) {
+ h->dtor(e->ptr);
+ e->ptr = NULL;
+ }
+
+ e->key_len = 0;
+
+ free(e);
+}
+
+/* return 1 on error, 0 is fine */
+int
+Curl_hash_init(struct curl_hash *h,
+ int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor)
+{
+ int i;
+
+ if(!slots || !hfunc || !comparator ||!dtor) {
+ return 1; /* failure */
+ }
+
+ h->hash_func = hfunc;
+ h->comp_func = comparator;
+ h->dtor = dtor;
+ h->size = 0;
+ h->slots = slots;
+
+ h->table = malloc(slots * sizeof(struct curl_llist *));
+ if(h->table) {
+ for(i = 0; i < slots; ++i) {
+ h->table[i] = Curl_llist_alloc((curl_llist_dtor) hash_element_dtor);
+ if(!h->table[i]) {
+ while(i--) {
+ Curl_llist_destroy(h->table[i], NULL);
+ h->table[i] = NULL;
+ }
+ free(h->table);
+ h->table = NULL;
+ h->slots = 0;
+ return 1; /* failure */
+ }
+ }
+ return 0; /* fine */
+ }
+ else {
+ h->slots = 0;
+ return 1; /* failure */
+ }
+}
+
+struct curl_hash *
+Curl_hash_alloc(int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor)
+{
+ struct curl_hash *h;
+
+ if(!slots || !hfunc || !comparator ||!dtor) {
+ return NULL; /* failure */
+ }
+
+ h = malloc(sizeof(struct curl_hash));
+ if(h) {
+ if(Curl_hash_init(h, slots, hfunc, comparator, dtor)) {
+ /* failure */
+ free(h);
+ h = NULL;
+ }
+ }
+
+ return h;
+}
+
+
+
+static struct curl_hash_element *
+mk_hash_element(const void *key, size_t key_len, const void *p)
+{
+ struct curl_hash_element *he = malloc(sizeof(struct curl_hash_element));
+
+ if(he) {
+ void *dupkey = malloc(key_len);
+ if(dupkey) {
+ /* copy the key */
+ memcpy(dupkey, key, key_len);
+
+ he->key = dupkey;
+ he->key_len = key_len;
+ he->ptr = (void *) p;
+ }
+ else {
+ /* failed to duplicate the key, free memory and fail */
+ free(he);
+ he = NULL;
+ }
+ }
+ return he;
+}
+
+#define FETCH_LIST(x,y,z) x->table[x->hash_func(y, z, x->slots)]
+
+/* Insert the data in the hash. If there already was a match in the hash,
+ * that data is replaced.
+ *
+ * @unittest: 1305
+ */
+void *
+Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p)
+{
+ struct curl_hash_element *he;
+ struct curl_llist_element *le;
+ struct curl_llist *l = FETCH_LIST (h, key, key_len);
+
+ for(le = l->head; le; le = le->next) {
+ he = (struct curl_hash_element *) le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ Curl_llist_remove(l, le, (void *)h);
+ --h->size;
+ break;
+ }
+ }
+
+ he = mk_hash_element(key, key_len, p);
+ if(he) {
+ if(Curl_llist_insert_next(l, l->tail, he)) {
+ ++h->size;
+ return p; /* return the new entry */
+ }
+ /*
+ * Couldn't insert it, destroy the 'he' element and the key again. We
+ * don't call hash_element_dtor() since that would also call the
+ * "destructor" for the actual data 'p'. When we fail, we shall not touch
+ * that data.
+ */
+ free(he->key);
+ free(he);
+ }
+
+ return NULL; /* failure */
+}
+
+/* remove the identified hash entry, returns non-zero on failure */
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len)
+{
+ struct curl_llist_element *le;
+ struct curl_hash_element *he;
+ struct curl_llist *l = FETCH_LIST(h, key, key_len);
+
+ for(le = l->head; le; le = le->next) {
+ he = le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ Curl_llist_remove(l, le, (void *) h);
+ --h->size;
+ return 0;
+ }
+ }
+ return 1;
+}
+
+void *
+Curl_hash_pick(struct curl_hash *h, void *key, size_t key_len)
+{
+ struct curl_llist_element *le;
+ struct curl_hash_element *he;
+ struct curl_llist *l;
+
+ if(h) {
+ l = FETCH_LIST(h, key, key_len);
+ for(le = l->head; le; le = le->next) {
+ he = le->ptr;
+ if(h->comp_func(he->key, he->key_len, key, key_len)) {
+ return he->ptr;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+#if defined(DEBUGBUILD) && defined(AGGRESIVE_TEST)
+void
+Curl_hash_apply(curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr))
+{
+ struct curl_llist_element *le;
+ int i;
+
+ for(i = 0; i < h->slots; ++i) {
+ for(le = (h->table[i])->head;
+ le;
+ le = le->next) {
+ curl_hash_element *el = le->ptr;
+ cb(user, el->ptr);
+ }
+ }
+}
+#endif
+
+void
+Curl_hash_clean(struct curl_hash *h)
+{
+ int i;
+
+ for(i = 0; i < h->slots; ++i) {
+ Curl_llist_destroy(h->table[i], (void *) h);
+ h->table[i] = NULL;
+ }
+
+ Curl_safefree(h->table);
+ h->size = 0;
+ h->slots = 0;
+}
+
+void
+Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+ int (*comp)(void *, void *))
+{
+ struct curl_llist_element *le;
+ struct curl_llist_element *lnext;
+ struct curl_llist *list;
+ int i;
+
+ if(!h)
+ return;
+
+ for(i = 0; i < h->slots; ++i) {
+ list = h->table[i];
+ le = list->head; /* get first list entry */
+ while(le) {
+ struct curl_hash_element *he = le->ptr;
+ lnext = le->next;
+ /* ask the callback function if we shall remove this entry or not */
+ if(comp(user, he->ptr)) {
+ Curl_llist_remove(list, le, (void *) h);
+ --h->size; /* one less entry in the hash now */
+ }
+ le = lnext;
+ }
+ }
+}
+
+void
+Curl_hash_destroy(struct curl_hash *h)
+{
+ if(!h)
+ return;
+
+ Curl_hash_clean(h);
+
+ free(h);
+}
+
+size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num)
+{
+ const char* key_str = (const char *) key;
+ const char *end = key_str + key_length;
+ unsigned long h = 5381;
+
+ while(key_str < end) {
+ h += h << 5;
+ h ^= (unsigned long) *key_str++;
+ }
+
+ return (h % slots_num);
+}
+
+size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2, size_t key2_len)
+{
+ char *key1 = (char *)k1;
+ char *key2 = (char *)k2;
+
+ if(key1_len == key2_len &&
+ *key1 == *key2 &&
+ memcmp(key1, key2, key1_len) == 0) {
+ return 1;
+ }
+
+ return 0;
+}
+
+void Curl_hash_start_iterate(struct curl_hash *hash,
+ struct curl_hash_iterator *iter)
+{
+ iter->hash = hash;
+ iter->slot_index = 0;
+ iter->current_element = NULL;
+}
+
+struct curl_hash_element *
+Curl_hash_next_element(struct curl_hash_iterator *iter)
+{
+ int i;
+ struct curl_hash *h = iter->hash;
+
+ /* Get the next element in the current list, if any */
+ if(iter->current_element)
+ iter->current_element = iter->current_element->next;
+
+ /* If we have reached the end of the list, find the next one */
+ if(!iter->current_element) {
+ for(i = iter->slot_index;i < h->slots;i++) {
+ if(h->table[i]->head) {
+ iter->current_element = h->table[i]->head;
+ iter->slot_index = i+1;
+ break;
+ }
+ }
+ }
+
+ if(iter->current_element) {
+ struct curl_hash_element *he = iter->current_element->ptr;
+ return he;
+ }
+ else {
+ iter->current_element = NULL;
+ return NULL;
+ }
+}
+
+#if 0 /* useful function for debugging hashes and their contents */
+void Curl_hash_print(struct curl_hash *h,
+ void (*func)(void *))
+{
+ struct curl_hash_iterator iter;
+ struct curl_hash_element *he;
+ int last_index = -1;
+
+ if(!h)
+ return;
+
+ fprintf(stderr, "=Hash dump=\n");
+
+ Curl_hash_start_iterate(h, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ if(iter.slot_index != last_index) {
+ fprintf(stderr, "index %d:", iter.slot_index);
+ if(last_index >= 0) {
+ fprintf(stderr, "\n");
+ }
+ last_index = iter.slot_index;
+ }
+
+ if(func)
+ func(he->ptr);
+ else
+ fprintf(stderr, " [%p]", (void *)he->ptr);
+
+ he = Curl_hash_next_element(&iter);
+ }
+ fprintf(stderr, "\n");
+}
+#endif
diff --git a/libs/libcurl/src/hash.h b/libs/libcurl/src/hash.h
new file mode 100644
index 0000000000..aa935d4eb9
--- /dev/null
+++ b/libs/libcurl/src/hash.h
@@ -0,0 +1,106 @@
+#ifndef HEADER_CURL_HASH_H
+#define HEADER_CURL_HASH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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 <stddef.h>
+
+#include "llist.h"
+
+/* Hash function prototype */
+typedef size_t (*hash_function) (void* key,
+ size_t key_length,
+ size_t slots_num);
+
+/*
+ Comparator function prototype. Compares two keys.
+*/
+typedef size_t (*comp_function) (void* key1,
+ size_t key1_len,
+ void*key2,
+ size_t key2_len);
+
+typedef void (*curl_hash_dtor)(void *);
+
+struct curl_hash {
+ struct curl_llist **table;
+
+ /* Hash function to be used for this hash table */
+ hash_function hash_func;
+
+ /* Comparator function to compare keys */
+ comp_function comp_func;
+ curl_hash_dtor dtor;
+ int slots;
+ size_t size;
+};
+
+struct curl_hash_element {
+ void *ptr;
+ char *key;
+ size_t key_len;
+};
+
+struct curl_hash_iterator {
+ struct curl_hash *hash;
+ int slot_index;
+ struct curl_llist_element *current_element;
+};
+
+int Curl_hash_init(struct curl_hash *h,
+ int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor);
+
+struct curl_hash *Curl_hash_alloc(int slots,
+ hash_function hfunc,
+ comp_function comparator,
+ curl_hash_dtor dtor);
+
+void *Curl_hash_add(struct curl_hash *h, void *key, size_t key_len, void *p);
+int Curl_hash_delete(struct curl_hash *h, void *key, size_t key_len);
+void *Curl_hash_pick(struct curl_hash *, void * key, size_t key_len);
+void Curl_hash_apply(struct curl_hash *h, void *user,
+ void (*cb)(void *user, void *ptr));
+int Curl_hash_count(struct curl_hash *h);
+void Curl_hash_clean(struct curl_hash *h);
+void Curl_hash_clean_with_criterium(struct curl_hash *h, void *user,
+ int (*comp)(void *, void *));
+void Curl_hash_destroy(struct curl_hash *h);
+
+size_t Curl_hash_str(void* key, size_t key_length, size_t slots_num);
+size_t Curl_str_key_compare(void*k1, size_t key1_len, void*k2,
+ size_t key2_len);
+
+void Curl_hash_start_iterate(struct curl_hash *hash,
+ struct curl_hash_iterator *iter);
+struct curl_hash_element *
+Curl_hash_next_element(struct curl_hash_iterator *iter);
+
+void Curl_hash_print(struct curl_hash *h,
+ void (*func)(void *));
+
+
+#endif /* HEADER_CURL_HASH_H */
diff --git a/libs/libcurl/src/hmac.c b/libs/libcurl/src/hmac.c
new file mode 100644
index 0000000000..dace820370
--- /dev/null
+++ b/libs/libcurl/src/hmac.c
@@ -0,0 +1,133 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ * RFC2104 Keyed-Hashing for Message Authentication
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include "curl_hmac.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"
+
+/*
+ * Generic HMAC algorithm.
+ *
+ * This module computes HMAC digests based on any hash function. Parameters
+ * and computing procedures are set-up dynamically at HMAC computation
+ * context initialisation.
+ */
+
+static const unsigned char hmac_ipad = 0x36;
+static const unsigned char hmac_opad = 0x5C;
+
+
+
+HMAC_context *
+Curl_HMAC_init(const HMAC_params * hashparams,
+ const unsigned char * key,
+ unsigned int keylen)
+{
+ size_t i;
+ HMAC_context * ctxt;
+ unsigned char * hkey;
+ unsigned char b;
+
+ /* Create HMAC context. */
+ i = sizeof *ctxt + 2 * hashparams->hmac_ctxtsize +
+ hashparams->hmac_resultlen;
+ ctxt = malloc(i);
+
+ if(!ctxt)
+ return ctxt;
+
+ ctxt->hmac_hash = hashparams;
+ ctxt->hmac_hashctxt1 = (void *) (ctxt + 1);
+ ctxt->hmac_hashctxt2 = (void *) ((char *) ctxt->hmac_hashctxt1 +
+ hashparams->hmac_ctxtsize);
+
+ /* If the key is too long, replace it by its hash digest. */
+ if(keylen > hashparams->hmac_maxkeylen) {
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, key, keylen);
+ hkey = (unsigned char *) ctxt->hmac_hashctxt2 + hashparams->hmac_ctxtsize;
+ (*hashparams->hmac_hfinal)(hkey, ctxt->hmac_hashctxt1);
+ key = hkey;
+ keylen = hashparams->hmac_resultlen;
+ }
+
+ /* Prime the two hash contexts with the modified key. */
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hinit)(ctxt->hmac_hashctxt2);
+
+ for(i = 0; i < keylen; i++) {
+ b = (unsigned char)(*key ^ hmac_ipad);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &b, 1);
+ b = (unsigned char)(*key++ ^ hmac_opad);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &b, 1);
+ }
+
+ for(; i < hashparams->hmac_maxkeylen; i++) {
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt1, &hmac_ipad, 1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2, &hmac_opad, 1);
+ }
+
+ /* Done, return pointer to HMAC context. */
+ return ctxt;
+}
+
+int Curl_HMAC_update(HMAC_context * ctxt,
+ const unsigned char * data,
+ unsigned int len)
+{
+ /* Update first hash calculation. */
+ (*ctxt->hmac_hash->hmac_hupdate)(ctxt->hmac_hashctxt1, data, len);
+ return 0;
+}
+
+
+int Curl_HMAC_final(HMAC_context * ctxt, unsigned char * result)
+{
+ const HMAC_params * hashparams = ctxt->hmac_hash;
+
+ /* Do not get result if called with a null parameter: only release
+ storage. */
+
+ if(!result)
+ result = (unsigned char *) ctxt->hmac_hashctxt2 +
+ ctxt->hmac_hash->hmac_ctxtsize;
+
+ (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt1);
+ (*hashparams->hmac_hupdate)(ctxt->hmac_hashctxt2,
+ result, hashparams->hmac_resultlen);
+ (*hashparams->hmac_hfinal)(result, ctxt->hmac_hashctxt2);
+ free((char *) ctxt);
+ return 0;
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/libs/libcurl/src/hostasyn.c b/libs/libcurl/src/hostasyn.c
new file mode 100644
index 0000000000..8151b6714e
--- /dev/null
+++ b/libs/libcurl/src/hostasyn.c
@@ -0,0 +1,157 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.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"
+
+/***********************************************************************
+ * Only for builds using asynchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_ASYNCH
+
+/*
+ * Curl_addrinfo_callback() gets called by ares, gethostbyname_thread()
+ * or getaddrinfo_thread() when we got the name resolved (or not!).
+ *
+ * If the status argument is CURL_ASYNC_SUCCESS, this function takes
+ * ownership of the Curl_addrinfo passed, storing the resolved data
+ * in the DNS cache.
+ *
+ * The storage operation locks and unlocks the DNS cache.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+ int status,
+ struct Curl_addrinfo *ai)
+{
+ struct Curl_dns_entry *dns = NULL;
+ CURLcode rc = CURLE_OK;
+
+ conn->async.status = status;
+
+ if(CURL_ASYNC_SUCCESS == status) {
+ if(ai) {
+ struct SessionHandle *data = conn->data;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns = Curl_cache_addr(data, ai,
+ conn->async.hostname,
+ conn->async.port);
+ if(!dns) {
+ /* failed to store, cleanup and return error */
+ Curl_freeaddrinfo(ai);
+ rc = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+ }
+ else {
+ rc = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ conn->async.dns = dns;
+
+ /* Set async.done TRUE last in this function since it may be used multi-
+ threaded and once this is TRUE the other thread may read fields from the
+ async struct */
+ conn->async.done = TRUE;
+
+ /* ipv4: The input hostent struct will be freed by ares when we return from
+ this function */
+ return rc;
+}
+
+/* Call this function after Curl_connect() has returned async=TRUE and
+ then a successful name resolve has been received.
+
+ Note: this function disconnects and frees the conn data in case of
+ resolve failure */
+CURLcode Curl_async_resolved(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode code;
+
+ if(conn->async.dns) {
+ conn->dns_entry = conn->async.dns;
+ conn->async.dns = NULL;
+ }
+
+ code = Curl_setup_conn(conn, protocol_done);
+
+ if(code)
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(conn, FALSE); /* close the connection */
+
+ return code;
+}
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ return Curl_resolver_getaddrinfo(conn, hostname, port, waitp);
+}
+
+#endif /* CURLRES_ASYNCH */
diff --git a/libs/libcurl/src/hostcheck.c b/libs/libcurl/src/hostcheck.c
new file mode 100644
index 0000000000..abd1fa0c3c
--- /dev/null
+++ b/libs/libcurl/src/hostcheck.c
@@ -0,0 +1,97 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#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"
+
+/*
+ * Match a hostname against a wildcard pattern.
+ * E.g.
+ * "foo.host.com" matches "*.host.com".
+ *
+ * We use the matching rule described in RFC6125, section 6.4.3.
+ * http://tools.ietf.org/html/rfc6125#section-6.4.3
+ */
+
+static int hostmatch(const char *hostname, const char *pattern)
+{
+ const char *pattern_label_end, *pattern_wildcard, *hostname_label_end;
+ int wildcard_enabled;
+ size_t prefixlen, suffixlen;
+ pattern_wildcard = strchr(pattern, '*');
+ if(pattern_wildcard == NULL)
+ return Curl_raw_equal(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ /* We require at least 2 dots in pattern to avoid too wide wildcard
+ match. */
+ wildcard_enabled = 1;
+ pattern_label_end = strchr(pattern, '.');
+ if(pattern_label_end == NULL || strchr(pattern_label_end+1, '.') == NULL ||
+ pattern_wildcard > pattern_label_end ||
+ Curl_raw_nequal(pattern, "xn--", 4)) {
+ wildcard_enabled = 0;
+ }
+ if(!wildcard_enabled)
+ return Curl_raw_equal(pattern, hostname) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+
+ hostname_label_end = strchr(hostname, '.');
+ if(hostname_label_end == NULL ||
+ !Curl_raw_equal(pattern_label_end, hostname_label_end))
+ return CURL_HOST_NOMATCH;
+
+ /* The wildcard must match at least one character, so the left-most
+ label of the hostname is at least as large as the left-most label
+ of the pattern. */
+ if(hostname_label_end - hostname < pattern_label_end - pattern)
+ return CURL_HOST_NOMATCH;
+
+ prefixlen = pattern_wildcard - pattern;
+ suffixlen = pattern_label_end - (pattern_wildcard+1);
+ return Curl_raw_nequal(pattern, hostname, prefixlen) &&
+ Curl_raw_nequal(pattern_wildcard+1, hostname_label_end - suffixlen,
+ suffixlen) ?
+ CURL_HOST_MATCH : CURL_HOST_NOMATCH;
+}
+
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname)
+{
+ if(!match_pattern || !*match_pattern ||
+ !hostname || !*hostname) /* sanity check */
+ return 0;
+
+ if(Curl_raw_equal(hostname, match_pattern)) /* trivial case */
+ return 1;
+
+ if(hostmatch(hostname,match_pattern) == CURL_HOST_MATCH)
+ return 1;
+ return 0;
+}
+
+#endif /* SSLEAY or AXTLS or QSOSSL or GSKIT */
diff --git a/libs/libcurl/src/hostcheck.h b/libs/libcurl/src/hostcheck.h
new file mode 100644
index 0000000000..f4a517a8e8
--- /dev/null
+++ b/libs/libcurl/src/hostcheck.h
@@ -0,0 +1,32 @@
+#ifndef HEADER_CURL_HOSTCHECK_H
+#define HEADER_CURL_HOSTCHECK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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/curl.h>
+
+#define CURL_HOST_NOMATCH 0
+#define CURL_HOST_MATCH 1
+int Curl_cert_hostcheck(const char *match_pattern, const char *hostname);
+
+#endif /* HEADER_CURL_HOSTCHECK_H */
+
diff --git a/libs/libcurl/src/hostip.c b/libs/libcurl/src/hostip.c
new file mode 100644
index 0000000000..f37b4925bb
--- /dev/null
+++ b/libs/libcurl/src/hostip.c
@@ -0,0 +1,827 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_ntop.h"
+#include "warnless.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"
+
+#if defined(CURLRES_SYNCH) && \
+ defined(HAVE_ALARM) && defined(SIGALRM) && defined(HAVE_SIGSETJMP)
+/* alarm-based timeouts can only be used with all the dependencies satisfied */
+#define USE_ALARM_TIMEOUT
+#endif
+
+/*
+ * hostip.c explained
+ * ==================
+ *
+ * The main COMPILE-TIME DEFINES to keep in mind when reading the host*.c
+ * source file are these:
+ *
+ * CURLRES_IPV6 - this host has getaddrinfo() and family, and thus we use
+ * that. The host may not be able to resolve IPv6, but we don't really have to
+ * take that into account. Hosts that aren't IPv6-enabled have CURLRES_IPV4
+ * defined.
+ *
+ * CURLRES_ARES - is defined if libcurl is built to use c-ares for
+ * asynchronous name resolves. This can be Windows or *nix.
+ *
+ * CURLRES_THREADED - is defined if libcurl is built to run under (native)
+ * Windows, and then the name resolve will be done in a new thread, and the
+ * supported API will be the same as for ares-builds.
+ *
+ * If any of the two previous are defined, CURLRES_ASYNCH is defined too. If
+ * libcurl is not built to use an asynchronous resolver, CURLRES_SYNCH is
+ * defined.
+ *
+ * The host*.c sources files are split up like this:
+ *
+ * hostip.c - method-independent resolver functions and utility functions
+ * hostasyn.c - functions for asynchronous name resolves
+ * hostsyn.c - functions for synchronous name resolves
+ * hostip4.c - ipv4-specific functions
+ * hostip6.c - ipv6-specific functions
+ *
+ * The two asynchronous name resolver backends are implemented in:
+ * asyn-ares.c - functions for ares-using name resolves
+ * asyn-thread.c - functions for threaded name resolves
+
+ * The hostip.h is the united header file for all this. It defines the
+ * CURLRES_* defines based on the config*.h and curl_setup.h defines.
+ */
+
+/* These two symbols are for the global DNS cache */
+static struct curl_hash hostname_cache;
+static int host_cache_initialized;
+
+static void freednsentry(void *freethis);
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void)
+{
+ int rc = 0;
+ if(!host_cache_initialized) {
+ rc = Curl_hash_init(&hostname_cache, 7, Curl_hash_str,
+ Curl_str_key_compare, freednsentry);
+ if(!rc)
+ host_cache_initialized = 1;
+ }
+ return rc?NULL:&hostname_cache;
+}
+
+/*
+ * Destroy and cleanup the global DNS cache
+ */
+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;
+ }
+}
+
+/*
+ * Return # of adresses in a Curl_addrinfo struct
+ */
+int Curl_num_addresses(const Curl_addrinfo *addr)
+{
+ int i = 0;
+ while(addr) {
+ addr = addr->ai_next;
+ i++;
+ }
+ return i;
+}
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ai' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ *
+ * If the conversion fails, it returns NULL.
+ */
+const char *
+Curl_printable_address(const Curl_addrinfo *ai, char *buf, size_t bufsize)
+{
+ const struct sockaddr_in *sa4;
+ const struct in_addr *ipaddr4;
+#ifdef ENABLE_IPV6
+ const struct sockaddr_in6 *sa6;
+ const struct in6_addr *ipaddr6;
+#endif
+
+ switch (ai->ai_family) {
+ case AF_INET:
+ sa4 = (const void *)ai->ai_addr;
+ ipaddr4 = &sa4->sin_addr;
+ return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr4, buf,
+ bufsize);
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ sa6 = (const void *)ai->ai_addr;
+ ipaddr6 = &sa6->sin6_addr;
+ return Curl_inet_ntop(ai->ai_family, (const void *)ipaddr6, buf,
+ bufsize);
+#endif
+ default:
+ break;
+ }
+ return NULL;
+}
+
+/*
+ * Return a hostcache id string for the provided host + port, to be used by
+ * the DNS caching.
+ */
+static char *
+create_hostcache_id(const char *name, int port)
+{
+ /* create and return the new allocated entry */
+ char *id = aprintf("%s:%d", name, port);
+ char *ptr = id;
+ if(ptr) {
+ /* lower case the name part */
+ while(*ptr && (*ptr != ':')) {
+ *ptr = (char)TOLOWER(*ptr);
+ ptr++;
+ }
+ }
+ return id;
+}
+
+struct hostcache_prune_data {
+ long cache_timeout;
+ time_t now;
+};
+
+/*
+ * This function is set as a callback to be called for every entry in the DNS
+ * cache when we want to prune old unused entries.
+ *
+ * Returning non-zero means remove the entry, return 0 to keep it in the
+ * cache.
+ */
+static int
+hostcache_timestamp_remove(void *datap, void *hc)
+{
+ struct hostcache_prune_data *data =
+ (struct hostcache_prune_data *) datap;
+ struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+
+ return (data->now - c->timestamp >= data->cache_timeout);
+}
+
+/*
+ * Prune the DNS cache. This assumes that a lock has already been taken.
+ */
+static void
+hostcache_prune(struct curl_hash *hostcache, long cache_timeout, time_t now)
+{
+ struct hostcache_prune_data user;
+
+ user.cache_timeout = cache_timeout;
+ user.now = now;
+
+ Curl_hash_clean_with_criterium(hostcache,
+ (void *) &user,
+ hostcache_timestamp_remove);
+}
+
+/*
+ * Library-wide function for pruning the DNS cache. This function takes and
+ * returns the appropriate locks.
+ */
+void Curl_hostcache_prune(struct SessionHandle *data)
+{
+ time_t now;
+
+ if((data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
+ /* cache forever means never prune, and NULL hostcache means
+ we can't do it */
+ return;
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ time(&now);
+
+ /* Remove outdated and unused entries from the hostcache */
+ hostcache_prune(data->dns.hostcache,
+ data->set.dns_cache_timeout,
+ now);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * Check if the entry should be pruned. Assumes a locked cache.
+ */
+static int
+remove_entry_if_stale(struct SessionHandle *data, struct Curl_dns_entry *dns)
+{
+ struct hostcache_prune_data user;
+
+ if(!dns || (data->set.dns_cache_timeout == -1) || !data->dns.hostcache)
+ /* cache forever means never prune, and NULL hostcache means
+ we can't do it */
+ return 0;
+
+ time(&user.now);
+ user.cache_timeout = data->set.dns_cache_timeout;
+
+ if(!hostcache_timestamp_remove(&user,dns) )
+ return 0;
+
+ Curl_hash_clean_with_criterium(data->dns.hostcache,
+ (void *) &user,
+ hostcache_timestamp_remove);
+
+ return 1;
+}
+
+
+#ifdef HAVE_SIGSETJMP
+/* Beware this is a global and unique instance. This is used to store the
+ return address that we can jump back to from inside a signal handler. This
+ is not thread-safe stuff. */
+sigjmp_buf curl_jmpenv;
+#endif
+
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * When calling Curl_resolv() has resulted in a response with a returned
+ * address, we call this function to store the information in the dns
+ * cache etc
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data,
+ Curl_addrinfo *addr,
+ const char *hostname,
+ int port)
+{
+ char *entry_id;
+ size_t entry_len;
+ struct Curl_dns_entry *dns;
+ struct Curl_dns_entry *dns2;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return NULL;
+ entry_len = strlen(entry_id);
+
+ /* Create a new cache entry */
+ dns = calloc(1, sizeof(struct Curl_dns_entry));
+ if(!dns) {
+ free(entry_id);
+ return NULL;
+ }
+
+ dns->inuse = 0; /* init to not used */
+ dns->addr = addr; /* this is the address(es) */
+ time(&dns->timestamp);
+ if(dns->timestamp == 0)
+ dns->timestamp = 1; /* zero indicates that entry isn't in hash table */
+
+ /* Store the resolved data in our DNS cache. */
+ dns2 = Curl_hash_add(data->dns.hostcache, entry_id, entry_len+1,
+ (void *)dns);
+ if(!dns2) {
+ free(dns);
+ free(entry_id);
+ return NULL;
+ }
+
+ dns = dns2;
+ dns->inuse++; /* mark entry as in-use */
+
+ /* free the allocated entry_id */
+ free(entry_id);
+
+ return dns;
+}
+
+/*
+ * Curl_resolv() is the main name resolve function within libcurl. It resolves
+ * a name and returns a pointer to the entry in the 'entry' argument (if one
+ * is provided). This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * In debug mode, we specifically test for an interface name "LocalHost"
+ * and resolve "localhost" instead as a means to permit test cases
+ * to connect to a local test server with any host name.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_ERROR (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ struct Curl_dns_entry **entry)
+{
+ char *entry_id = NULL;
+ struct Curl_dns_entry *dns = NULL;
+ size_t entry_len;
+ struct SessionHandle *data = conn->data;
+ CURLcode result;
+ int rc = CURLRESOLV_ERROR; /* default to failure */
+
+ *entry = NULL;
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id)
+ return rc;
+
+ entry_len = strlen(entry_id);
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ /* See whether the returned entry is stale. Done before we release lock */
+ if(remove_entry_if_stale(data, dns))
+ dns = NULL; /* the memory deallocation is being handled by the hash */
+
+ if(dns) {
+ dns->inuse++; /* we use it! */
+ rc = CURLRESOLV_RESOLVED;
+ }
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns) {
+ /* The entry was not in the cache. Resolve it to IP address */
+
+ Curl_addrinfo *addr;
+ int respwait;
+
+ /* Check what IP specifics the app has requested and if we can provide it.
+ * If not, bail out. */
+ if(!Curl_ipvalid(conn))
+ return CURLRESOLV_ERROR;
+
+ /* If Curl_getaddrinfo() returns NULL, 'respwait' might be set to a
+ non-zero value indicating that we need to wait for the response to the
+ resolve call */
+ addr = Curl_getaddrinfo(conn,
+#ifdef DEBUGBUILD
+ (data->set.str[STRING_DEVICE]
+ && !strcmp(data->set.str[STRING_DEVICE],
+ "LocalHost"))?"localhost":
+#endif
+ hostname, port, &respwait);
+
+ if(!addr) {
+ if(respwait) {
+ /* the response to our resolve call will come asynchronously at
+ a later time, good or bad */
+ /* First, check that we haven't received the info by now */
+ result = Curl_resolver_is_resolved(conn, &dns);
+ if(result) /* error detected */
+ return CURLRESOLV_ERROR;
+ if(dns)
+ rc = CURLRESOLV_RESOLVED; /* pointer provided */
+ else
+ rc = CURLRESOLV_PENDING; /* no info yet */
+ }
+ }
+ else {
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* we got a response, store it in the cache */
+ dns = Curl_cache_addr(data, addr, hostname, port);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns)
+ /* returned failure, bail out nicely */
+ Curl_freeaddrinfo(addr);
+ else
+ rc = CURLRESOLV_RESOLVED;
+ }
+ }
+
+ *entry = dns;
+
+ return rc;
+}
+
+#ifdef USE_ALARM_TIMEOUT
+/*
+ * This signal handler jumps back into the main libcurl code and continues
+ * execution. This effectively causes the remainder of the application to run
+ * within a signal handler which is nonportable and could lead to problems.
+ */
+static
+RETSIGTYPE alarmfunc(int sig)
+{
+ /* this is for "-ansi -Wall -pedantic" to stop complaining! (rabe) */
+ (void)sig;
+ siglongjmp(curl_jmpenv, 1);
+ return;
+}
+#endif /* USE_ALARM_TIMEOUT */
+
+/*
+ * Curl_resolv_timeout() is the same as Curl_resolv() but specifies a
+ * timeout. This function might return immediately if we're using asynch
+ * resolves. See the return codes.
+ *
+ * The cache entry we return will get its 'inuse' counter increased when this
+ * function is used. You MUST call Curl_resolv_unlock() later (when you're
+ * done using this struct) to decrease the counter again.
+ *
+ * If built with a synchronous resolver and use of signals is not
+ * disabled by the application, then a nonzero timeout will cause a
+ * timeout after the specified number of milliseconds. Otherwise, timeout
+ * is ignored.
+ *
+ * Return codes:
+ *
+ * CURLRESOLV_TIMEDOUT(-2) = warning, time too short or previous alarm expired
+ * CURLRESOLV_ERROR (-1) = error, no pointer
+ * CURLRESOLV_RESOLVED (0) = OK, pointer provided
+ * CURLRESOLV_PENDING (1) = waiting for response, no pointer
+ */
+
+int Curl_resolv_timeout(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ struct Curl_dns_entry **entry,
+ long timeoutms)
+{
+#ifdef USE_ALARM_TIMEOUT
+#ifdef HAVE_SIGACTION
+ struct sigaction keep_sigact; /* store the old struct here */
+ volatile bool keep_copysig = FALSE; /* wether old sigact has been saved */
+ struct sigaction sigact;
+#else
+#ifdef HAVE_SIGNAL
+ void (*keep_sigact)(int); /* store the old handler here */
+#endif /* HAVE_SIGNAL */
+#endif /* HAVE_SIGACTION */
+ volatile long timeout;
+ volatile unsigned int prev_alarm = 0;
+ struct SessionHandle *data = conn->data;
+#endif /* USE_ALARM_TIMEOUT */
+ int rc;
+
+ *entry = NULL;
+
+ if(timeoutms < 0)
+ /* got an already expired timeout */
+ return CURLRESOLV_TIMEDOUT;
+
+#ifdef USE_ALARM_TIMEOUT
+ if(data->set.no_signal)
+ /* Ignore the timeout when signals are disabled */
+ timeout = 0;
+ else
+ timeout = timeoutms;
+
+ if(!timeout)
+ /* USE_ALARM_TIMEOUT defined, but no timeout actually requested */
+ return Curl_resolv(conn, hostname, port, entry);
+
+ if(timeout < 1000)
+ /* The alarm() function only provides integer second resolution, so if
+ we want to wait less than one second we must bail out already now. */
+ return CURLRESOLV_TIMEDOUT;
+
+ /*************************************************************
+ * Set signal handler to catch SIGALRM
+ * Store the old value to be able to set it back later!
+ *************************************************************/
+#ifdef HAVE_SIGACTION
+ sigaction(SIGALRM, NULL, &sigact);
+ keep_sigact = sigact;
+ keep_copysig = TRUE; /* yes, we have a copy */
+ sigact.sa_handler = alarmfunc;
+#ifdef SA_RESTART
+ /* HPUX doesn't have SA_RESTART but defaults to that behaviour! */
+ sigact.sa_flags &= ~SA_RESTART;
+#endif
+ /* now set the new struct */
+ sigaction(SIGALRM, &sigact, NULL);
+#else /* HAVE_SIGACTION */
+ /* no sigaction(), revert to the much lamer signal() */
+#ifdef HAVE_SIGNAL
+ keep_sigact = signal(SIGALRM, alarmfunc);
+#endif
+#endif /* HAVE_SIGACTION */
+
+ /* alarm() makes a signal get sent when the timeout fires off, and that
+ will abort system calls */
+ prev_alarm = alarm(curlx_sltoui(timeout/1000L));
+
+ /* This allows us to time-out from the name resolver, as the timeout
+ will generate a signal and we will siglongjmp() from that here.
+ This technique has problems (see alarmfunc).
+ This should be the last thing we do before calling Curl_resolv(),
+ as otherwise we'd have to worry about variables that get modified
+ before we invoke Curl_resolv() (and thus use "volatile"). */
+ if(sigsetjmp(curl_jmpenv, 1)) {
+ /* this is coming from a siglongjmp() after an alarm signal */
+ failf(data, "name lookup timed out");
+ rc = CURLRESOLV_ERROR;
+ goto clean_up;
+ }
+
+#else
+#ifndef CURLRES_ASYNCH
+ if(timeoutms)
+ infof(conn->data, "timeout on name lookup is not supported\n");
+#else
+ (void)timeoutms; /* timeoutms not used with an async resolver */
+#endif
+#endif /* USE_ALARM_TIMEOUT */
+
+ /* Perform the actual name resolution. This might be interrupted by an
+ * alarm if it takes too long.
+ */
+ rc = Curl_resolv(conn, hostname, port, entry);
+
+#ifdef USE_ALARM_TIMEOUT
+clean_up:
+
+ if(!prev_alarm)
+ /* deactivate a possibly active alarm before uninstalling the handler */
+ alarm(0);
+
+#ifdef HAVE_SIGACTION
+ if(keep_copysig) {
+ /* we got a struct as it looked before, now put that one back nice
+ and clean */
+ sigaction(SIGALRM, &keep_sigact, NULL); /* put it back */
+ }
+#else
+#ifdef HAVE_SIGNAL
+ /* restore the previous SIGALRM handler */
+ signal(SIGALRM, keep_sigact);
+#endif
+#endif /* HAVE_SIGACTION */
+
+ /* switch back the alarm() to either zero or to what it was before minus
+ the time we spent until now! */
+ if(prev_alarm) {
+ /* there was an alarm() set before us, now put it back */
+ unsigned long elapsed_ms = Curl_tvdiff(Curl_tvnow(), conn->created);
+
+ /* the alarm period is counted in even number of seconds */
+ unsigned long alarm_set = prev_alarm - elapsed_ms/1000;
+
+ if(!alarm_set ||
+ ((alarm_set >= 0x80000000) && (prev_alarm < 0x80000000)) ) {
+ /* if the alarm time-left reached zero or turned "negative" (counted
+ with unsigned values), we should fire off a SIGALRM here, but we
+ won't, and zero would be to switch it off so we never set it to
+ less than 1! */
+ alarm(1);
+ rc = CURLRESOLV_TIMEDOUT;
+ failf(data, "Previous alarm fired off!");
+ }
+ else
+ alarm((unsigned int)alarm_set);
+ }
+#endif /* USE_ALARM_TIMEOUT */
+
+ return rc;
+}
+
+/*
+ * 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 && data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ dns->inuse--;
+ /* only free if nobody is using AND it is not in hostcache (timestamp ==
+ 0) */
+ if(dns->inuse == 0 && dns->timestamp == 0) {
+ Curl_freeaddrinfo(dns->addr);
+ free(dns);
+ }
+
+ if(data && data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+}
+
+/*
+ * File-internal: free a cache dns entry.
+ */
+static void freednsentry(void *freethis)
+{
+ struct Curl_dns_entry *p = (struct Curl_dns_entry *) freethis;
+
+ /* mark the entry as not in hostcache */
+ p->timestamp = 0;
+ if(p->inuse == 0) {
+ Curl_freeaddrinfo(p->addr);
+ free(p);
+ }
+}
+
+/*
+ * Curl_mk_dnscache() creates a new DNS cache and returns the handle for it.
+ */
+struct curl_hash *Curl_mk_dnscache(void)
+{
+ return Curl_hash_alloc(7, Curl_hash_str, Curl_str_key_compare, freednsentry);
+}
+
+static int hostcache_inuse(void *data, void *hc)
+{
+ struct Curl_dns_entry *c = (struct Curl_dns_entry *) hc;
+
+ if(c->inuse == 1)
+ Curl_resolv_unlock(data, c);
+
+ return 1; /* free all entries */
+}
+
+/*
+ * 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(hash, data, hostcache_inuse);
+}
+
+
+CURLcode Curl_loadhostpairs(struct SessionHandle *data)
+{
+ struct curl_slist *hostp;
+ char hostname[256];
+ char address[256];
+ int port;
+
+ for(hostp = data->change.resolve; hostp; hostp = hostp->next ) {
+ if(!hostp->data)
+ continue;
+ if(hostp->data[0] == '-') {
+ /* TODO: mark an entry for removal */
+ }
+ else if(3 == sscanf(hostp->data, "%255[^:]:%d:%255s", hostname, &port,
+ address)) {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *addr;
+ char *entry_id;
+ size_t entry_len;
+
+ addr = Curl_str2addr(address, port);
+ if(!addr) {
+ infof(data, "Resolve %s found illegal!\n", hostp->data);
+ continue;
+ }
+
+ /* Create an entry id, based upon the hostname and port */
+ entry_id = create_hostcache_id(hostname, port);
+ /* If we can't create the entry id, fail */
+ if(!entry_id) {
+ Curl_freeaddrinfo(addr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ entry_len = strlen(entry_id);
+
+ if(data->share)
+ Curl_share_lock(data, CURL_LOCK_DATA_DNS, CURL_LOCK_ACCESS_SINGLE);
+
+ /* See if its already in our dns cache */
+ dns = Curl_hash_pick(data->dns.hostcache, entry_id, entry_len+1);
+
+ /* free the allocated entry_id again */
+ free(entry_id);
+
+ if(!dns)
+ /* if not in the cache already, put this host in the cache */
+ dns = Curl_cache_addr(data, addr, hostname, port);
+ else
+ /* this is a duplicate, free it again */
+ Curl_freeaddrinfo(addr);
+
+ if(data->share)
+ Curl_share_unlock(data, CURL_LOCK_DATA_DNS);
+
+ if(!dns) {
+ Curl_freeaddrinfo(addr);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ infof(data, "Added %s:%d:%s to DNS cache\n",
+ hostname, port, address);
+ }
+ }
+ data->change.resolve = NULL; /* dealt with now */
+
+ return CURLE_OK;
+}
diff --git a/libs/libcurl/src/hostip.h b/libs/libcurl/src/hostip.h
new file mode 100644
index 0000000000..42ed7d3208
--- /dev/null
+++ b/libs/libcurl/src/hostip.h
@@ -0,0 +1,239 @@
+#ifndef HEADER_CURL_HOSTIP_H
+#define HEADER_CURL_HOSTIP_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"
+#include "hash.h"
+#include "curl_addrinfo.h"
+#include "asyn.h"
+
+#ifdef HAVE_SETJMP_H
+#include <setjmp.h>
+#endif
+
+#ifdef NETWARE
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+/* Allocate enough memory to hold the full name information structs and
+ * everything. OSF1 is known to require at least 8872 bytes. The buffer
+ * required for storing all possible aliases and IP numbers is according to
+ * Stevens' Unix Network Programming 2nd edition, p. 304: 8192 bytes!
+ */
+#define CURL_HOSTENT_SIZE 9000
+
+#define CURL_TIMEOUT_RESOLVE 300 /* when using asynch methods, we allow this
+ many seconds for a name resolve */
+
+#define CURL_ASYNC_SUCCESS CURLE_OK
+
+struct addrinfo;
+struct hostent;
+struct SessionHandle;
+struct connectdata;
+
+/*
+ * Curl_global_host_cache_init() initializes and sets up a global DNS cache.
+ * Global DNS cache is general badness. Do not use. This will be removed in
+ * a future version. Use the share interface instead!
+ *
+ * Returns a struct curl_hash pointer on success, NULL on failure.
+ */
+struct curl_hash *Curl_global_host_cache_init(void);
+void Curl_global_host_cache_dtor(void);
+
+struct Curl_dns_entry {
+ Curl_addrinfo *addr;
+ /* timestamp == 0 -- entry not in hostcache
+ timestamp != 0 -- entry is in hostcache */
+ time_t timestamp;
+ long inuse; /* use-counter, make very sure you decrease this
+ when you're done using the address you received */
+};
+
+/*
+ * Curl_resolv() returns an entry with the info for the specified host
+ * and port.
+ *
+ * The returned data *MUST* be "unlocked" with Curl_resolv_unlock() after
+ * use, or we'll leak memory!
+ */
+/* return codes */
+#define CURLRESOLV_TIMEDOUT -2
+#define CURLRESOLV_ERROR -1
+#define CURLRESOLV_RESOLVED 0
+#define CURLRESOLV_PENDING 1
+int Curl_resolv(struct connectdata *conn, const char *hostname,
+ int port, struct Curl_dns_entry **dnsentry);
+int Curl_resolv_timeout(struct connectdata *conn, const char *hostname,
+ int port, struct Curl_dns_entry **dnsentry,
+ long timeoutms);
+
+#ifdef CURLRES_IPV6
+/*
+ * Curl_ipv6works() returns TRUE if ipv6 seems to work.
+ */
+bool Curl_ipv6works(void);
+#else
+#define Curl_ipv6works() FALSE
+#endif
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn);
+
+
+/*
+ * Curl_getaddrinfo() is the generic low-level name resolve API within this
+ * source file. There are several versions of this function - for different
+ * name resolve layers (selected at build-time). They all take this same set
+ * of arguments
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp);
+
+
+/* unlock a previously resolved dns entry */
+void Curl_resolv_unlock(struct SessionHandle *data,
+ struct Curl_dns_entry *dns);
+
+/* for debugging purposes only: */
+void Curl_scan_cache_used(void *user, void *ptr);
+
+/* make a new dns cache and return the handle */
+struct curl_hash *Curl_mk_dnscache(void);
+
+/* prune old entries from the DNS cache */
+void Curl_hostcache_prune(struct SessionHandle *data);
+
+/* Return # of adresses in a Curl_addrinfo struct */
+int Curl_num_addresses (const Curl_addrinfo *addr);
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+ GETNAMEINFO_TYPE_ARG2 salen,
+ char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+ char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+ GETNAMEINFO_TYPE_ARG7 flags,
+ int line, const char *source);
+#endif
+
+/* IPv4 threadsafe resolve function used for synch and asynch builds */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char * hostname, int port);
+
+CURLcode Curl_async_resolved(struct connectdata *conn,
+ bool *protocol_connect);
+
+#ifndef CURLRES_ASYNCH
+#define Curl_async_resolved(x,y) CURLE_OK
+#endif
+
+/*
+ * Curl_addrinfo_callback() is used when we build with any asynch specialty.
+ * Handles end of async request processing. Inserts ai into hostcache when
+ * status is CURL_ASYNC_SUCCESS. Twiddles fields in conn to indicate async
+ * request completed whether successful or failed.
+ */
+CURLcode Curl_addrinfo_callback(struct connectdata *conn,
+ int status,
+ Curl_addrinfo *ai);
+
+/*
+ * Curl_printable_address() returns a printable version of the 1st address
+ * given in the 'ip' argument. The result will be stored in the buf that is
+ * bufsize bytes big.
+ */
+const char *Curl_printable_address(const Curl_addrinfo *ip,
+ char *buf, size_t bufsize);
+
+/*
+ * Curl_cache_addr() stores a 'Curl_addrinfo' struct in the DNS cache.
+ *
+ * Returns the Curl_dns_entry entry pointer or NULL if the storage failed.
+ */
+struct Curl_dns_entry *
+Curl_cache_addr(struct SessionHandle *data, Curl_addrinfo *addr,
+ const char *hostname, int port);
+
+#ifndef INADDR_NONE
+#define CURL_INADDR_NONE (in_addr_t) ~0
+#else
+#define CURL_INADDR_NONE INADDR_NONE
+#endif
+
+#ifdef HAVE_SIGSETJMP
+/* Forward-declaration of variable defined in hostip.c. Beware this
+ * is a global and unique instance. This is used to store the return
+ * address that we can jump back to from inside a signal handler.
+ * This is not thread-safe stuff.
+ */
+extern sigjmp_buf curl_jmpenv;
+#endif
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+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, struct curl_hash *hash);
+
+/*
+ * Destroy the hostcache of this handle.
+ */
+void Curl_hostcache_destroy(struct SessionHandle *data);
+
+/*
+ * Populate the cache with specified entries from CURLOPT_RESOLVE.
+ */
+CURLcode Curl_loadhostpairs(struct SessionHandle *data);
+
+#endif /* HEADER_CURL_HOSTIP_H */
diff --git a/libs/libcurl/src/hostip4.c b/libs/libcurl/src/hostip4.c
new file mode 100644
index 0000000000..1e39f4a987
--- /dev/null
+++ b/libs/libcurl/src/hostip4.c
@@ -0,0 +1,310 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.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"
+
+/***********************************************************************
+ * Only for plain-ipv4 builds
+ **********************************************************************/
+#ifdef CURLRES_IPV4 /* plain ipv4 code coming up */
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn)
+{
+ if(conn->ip_version == CURL_IPRESOLVE_V6)
+ /* an ipv6 address was requested and we can't get/use one */
+ return FALSE;
+
+ return TRUE; /* OK, proceed */
+}
+
+#ifdef CURLRES_SYNCH
+
+/*
+ * Curl_getaddrinfo() - the ipv4 synchronous version.
+ *
+ * The original code to this function was from the Dancer source code, written
+ * by Bjorn Reese, it has since been patched and modified considerably.
+ *
+ * gethostbyname_r() is the thread-safe version of the gethostbyname()
+ * function. When we build for plain IPv4, we attempt to use this
+ * function. There are _three_ different gethostbyname_r() versions, and we
+ * detect which one this platform supports in the configure script and set up
+ * the HAVE_GETHOSTBYNAME_R_3, HAVE_GETHOSTBYNAME_R_5 or
+ * HAVE_GETHOSTBYNAME_R_6 defines accordingly. Note that HAVE_GETADDRBYNAME
+ * has the corresponding rules. This is primarily on *nix. Note that some unix
+ * flavours have thread-safe versions of the plain gethostbyname() etc.
+ *
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ Curl_addrinfo *ai = NULL;
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+ (void)conn;
+#endif
+
+ *waitp = 0; /* synchronous response only */
+
+ ai = Curl_ipv4_resolve_r(hostname, port);
+ if(!ai)
+ infof(conn->data, "Curl_ipv4_resolve_r failed for %s\n", hostname);
+
+ return ai;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV4 */
+
+#if defined(CURLRES_IPV4) && !defined(CURLRES_ARES)
+
+/*
+ * Curl_ipv4_resolve_r() - ipv4 threadsafe resolver function.
+ *
+ * This is used for both synchronous and asynchronous resolver builds,
+ * implying that only threadsafe code and function calls may be used.
+ *
+ */
+Curl_addrinfo *Curl_ipv4_resolve_r(const char *hostname,
+ int port)
+{
+#if !defined(HAVE_GETADDRINFO_THREADSAFE) && defined(HAVE_GETHOSTBYNAME_R_3)
+ int res;
+#endif
+ Curl_addrinfo *ai = NULL;
+ struct hostent *h = NULL;
+ struct in_addr in;
+ struct hostent *buf = NULL;
+
+ if(Curl_inet_pton(AF_INET, hostname, &in) > 0)
+ /* This is a dotted IP address 123.123.123.123-style */
+ return Curl_ip2addr(AF_INET, &in, hostname, port);
+
+#if defined(HAVE_GETADDRINFO_THREADSAFE)
+ else {
+ struct addrinfo hints;
+ char sbuf[12];
+ char *sbufptr = NULL;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = PF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ if(port) {
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+ sbufptr = sbuf;
+ }
+
+ (void)Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &ai);
+
+#elif defined(HAVE_GETHOSTBYNAME_R)
+ /*
+ * gethostbyname_r() is the preferred resolve function for many platforms.
+ * Since there are three different versions of it, the following code is
+ * somewhat #ifdef-ridden.
+ */
+ else {
+ int h_errnop;
+
+ buf = calloc(1, CURL_HOSTENT_SIZE);
+ if(!buf)
+ return NULL; /* major failure */
+ /*
+ * The clearing of the buffer is a workaround for a gethostbyname_r bug in
+ * qnx nto and it is also _required_ for some of these functions on some
+ * platforms.
+ */
+
+#if defined(HAVE_GETHOSTBYNAME_R_5)
+ /* Solaris, IRIX and more */
+ h = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h_errnop);
+
+ /* If the buffer is too small, it returns NULL and sets errno to
+ * ERANGE. The errno is thread safe if this is compiled with
+ * -D_REENTRANT as then the 'errno' variable is a macro defined to get
+ * used properly for threads.
+ */
+
+ if(h) {
+ ;
+ }
+ else
+#elif defined(HAVE_GETHOSTBYNAME_R_6)
+ /* Linux */
+
+ (void)gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (char *)buf + sizeof(struct hostent),
+ CURL_HOSTENT_SIZE - sizeof(struct hostent),
+ &h, /* DIFFERENCE */
+ &h_errnop);
+ /* Redhat 8, using glibc 2.2.93 changed the behavior. Now all of a
+ * sudden this function returns EAGAIN if the given buffer size is too
+ * small. Previous versions are known to return ERANGE for the same
+ * problem.
+ *
+ * This wouldn't be such a big problem if older versions wouldn't
+ * sometimes return EAGAIN on a common failure case. Alas, we can't
+ * assume that EAGAIN *or* ERANGE means ERANGE for any given version of
+ * glibc.
+ *
+ * For now, we do that and thus we may call the function repeatedly and
+ * fail for older glibc versions that return EAGAIN, until we run out of
+ * buffer size (step_size grows beyond CURL_HOSTENT_SIZE).
+ *
+ * If anyone has a better fix, please tell us!
+ *
+ * -------------------------------------------------------------------
+ *
+ * On October 23rd 2003, Dan C dug up more details on the mysteries of
+ * gethostbyname_r() in glibc:
+ *
+ * In glibc 2.2.5 the interface is different (this has also been
+ * discovered in glibc 2.1.1-6 as shipped by Redhat 6). What I can't
+ * explain, is that tests performed on glibc 2.2.4-34 and 2.2.4-32
+ * (shipped/upgraded by Redhat 7.2) don't show this behavior!
+ *
+ * In this "buggy" version, the return code is -1 on error and 'errno'
+ * is set to the ERANGE or EAGAIN code. Note that 'errno' is not a
+ * thread-safe variable.
+ */
+
+ if(!h) /* failure */
+#elif defined(HAVE_GETHOSTBYNAME_R_3)
+ /* AIX, Digital Unix/Tru64, HPUX 10, more? */
+
+ /* For AIX 4.3 or later, we don't use gethostbyname_r() at all, because of
+ * the plain fact that it does not return unique full buffers on each
+ * call, but instead several of the pointers in the hostent structs will
+ * point to the same actual data! This have the unfortunate down-side that
+ * our caching system breaks down horribly. Luckily for us though, AIX 4.3
+ * and more recent versions have a "completely thread-safe"[*] libc where
+ * all the data is stored in thread-specific memory areas making calls to
+ * the plain old gethostbyname() work fine even for multi-threaded
+ * programs.
+ *
+ * This AIX 4.3 or later detection is all made in the configure script.
+ *
+ * Troels Walsted Hansen helped us work this out on March 3rd, 2003.
+ *
+ * [*] = much later we've found out that it isn't at all "completely
+ * thread-safe", but at least the gethostbyname() function is.
+ */
+
+ if(CURL_HOSTENT_SIZE >=
+ (sizeof(struct hostent)+sizeof(struct hostent_data))) {
+
+ /* August 22nd, 2000: Albert Chin-A-Young brought an updated version
+ * that should work! September 20: Richard Prescott worked on the buffer
+ * size dilemma.
+ */
+
+ res = gethostbyname_r(hostname,
+ (struct hostent *)buf,
+ (struct hostent_data *)((char *)buf +
+ sizeof(struct hostent)));
+ h_errnop = SOCKERRNO; /* we don't deal with this, but set it anyway */
+ }
+ else
+ res = -1; /* failure, too smallish buffer size */
+
+ if(!res) { /* success */
+
+ h = buf; /* result expected in h */
+
+ /* This is the worst kind of the different gethostbyname_r() interfaces.
+ * Since we don't know how big buffer this particular lookup required,
+ * we can't realloc down the huge alloc without doing closer analysis of
+ * the returned data. Thus, we always use CURL_HOSTENT_SIZE for every
+ * name lookup. Fixing this would require an extra malloc() and then
+ * calling Curl_addrinfo_copy() that subsequent realloc()s down the new
+ * memory area to the actually used amount.
+ */
+ }
+ else
+#endif /* HAVE_...BYNAME_R_5 || HAVE_...BYNAME_R_6 || HAVE_...BYNAME_R_3 */
+ {
+ h = NULL; /* set return code to NULL */
+ free(buf);
+ }
+#else /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+ /*
+ * Here is code for platforms that don't have a thread safe
+ * getaddrinfo() nor gethostbyname_r() function or for which
+ * gethostbyname() is the preferred one.
+ */
+ else {
+ h = gethostbyname((void*)hostname);
+#endif /* HAVE_GETADDRINFO_THREADSAFE || HAVE_GETHOSTBYNAME_R */
+ }
+
+ if(h) {
+ ai = Curl_he2ai(h, port);
+
+ if(buf) /* used a *_r() function */
+ free(buf);
+ }
+
+ return ai;
+}
+#endif /* defined(CURLRES_IPV4) && !defined(CURLRES_ARES) */
diff --git a/libs/libcurl/src/hostip6.c b/libs/libcurl/src/hostip6.c
new file mode 100644
index 0000000000..8327004cd3
--- /dev/null
+++ b/libs/libcurl/src/hostip6.c
@@ -0,0 +1,224 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.h"
+#include "inet_pton.h"
+#include "connect.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"
+
+/***********************************************************************
+ * Only for ipv6-enabled builds
+ **********************************************************************/
+#ifdef CURLRES_IPV6
+
+
+#if defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO)
+/* These are strictly for memory tracing and are using the same style as the
+ * family otherwise present in memdebug.c. I put these ones here since they
+ * require a bunch of structs I didn't want to include in memdebug.c
+ */
+
+/*
+ * For CURLRES_ARS, this should be written using ares_gethostbyaddr()
+ * (ignoring the fact c-ares doesn't return 'serv').
+ */
+
+int curl_dogetnameinfo(GETNAMEINFO_QUAL_ARG1 GETNAMEINFO_TYPE_ARG1 sa,
+ GETNAMEINFO_TYPE_ARG2 salen,
+ char *host, GETNAMEINFO_TYPE_ARG46 hostlen,
+ char *serv, GETNAMEINFO_TYPE_ARG46 servlen,
+ GETNAMEINFO_TYPE_ARG7 flags,
+ int line, const char *source)
+{
+ int res = (getnameinfo)(sa, salen,
+ host, hostlen,
+ serv, servlen,
+ flags);
+ if(0 == res)
+ /* success */
+ curl_memlog("GETNAME %s:%d getnameinfo()\n",
+ source, line);
+ else
+ curl_memlog("GETNAME %s:%d getnameinfo() failed = %d\n",
+ source, line, res);
+ return res;
+}
+#endif /* defined(CURLDEBUG) && defined(HAVE_GETNAMEINFO) */
+
+/*
+ * Curl_ipv6works() returns TRUE if ipv6 seems to work.
+ */
+bool Curl_ipv6works(void)
+{
+ /* the nature of most system is that IPv6 status doesn't come and go
+ during a program's lifetime so we only probe the first time and then we
+ have the info kept for fast re-use */
+ static int ipv6_works = -1;
+ if(-1 == ipv6_works) {
+ /* probe to see if we have a working IPv6 stack */
+ curl_socket_t s = socket(PF_INET6, SOCK_DGRAM, 0);
+ if(s == CURL_SOCKET_BAD)
+ /* an ipv6 address was requested but we can't get/use one */
+ ipv6_works = 0;
+ else {
+ ipv6_works = 1;
+ Curl_closesocket(NULL, s);
+ }
+ }
+ return (ipv6_works>0)?TRUE:FALSE;
+}
+
+/*
+ * Curl_ipvalid() checks what CURL_IPRESOLVE_* requirements that might've
+ * been set and returns TRUE if they are OK.
+ */
+bool Curl_ipvalid(struct connectdata *conn)
+{
+ if(conn->ip_version == CURL_IPRESOLVE_V6)
+ return Curl_ipv6works();
+ return TRUE;
+}
+
+#if defined(CURLRES_SYNCH)
+
+#ifdef DEBUG_ADDRINFO
+static void dump_addrinfo(struct connectdata *conn, const Curl_addrinfo *ai)
+{
+ printf("dump_addrinfo:\n");
+ for(; ai; ai = ai->ai_next) {
+ char buf[INET6_ADDRSTRLEN];
+
+ printf(" fam %2d, CNAME %s, ",
+ ai->ai_family, ai->ai_canonname ? ai->ai_canonname : "<none>");
+ if(Curl_printable_address(ai, buf, sizeof(buf)))
+ printf("%s\n", buf);
+ else
+ printf("failed; %s\n", Curl_strerror(conn, SOCKERRNO));
+ }
+}
+#else
+#define dump_addrinfo(x,y) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_getaddrinfo() when built ipv6-enabled (non-threading and
+ * non-ares version).
+ *
+ * Returns name information about the given hostname and port number. If
+ * successful, the 'addrinfo' is returned and the forth argument will point to
+ * memory we need to free after use. That memory *MUST* be freed with
+ * Curl_freeaddrinfo(), nothing else.
+ */
+Curl_addrinfo *Curl_getaddrinfo(struct connectdata *conn,
+ const char *hostname,
+ int port,
+ int *waitp)
+{
+ struct addrinfo hints;
+ Curl_addrinfo *res;
+ int error;
+ char sbuf[12];
+ char *sbufptr = NULL;
+ char addrbuf[128];
+ int pf;
+ struct SessionHandle *data = conn->data;
+
+ *waitp = 0; /* synchronous response only */
+
+ /*
+ * Check if a limited name resolve has been requested.
+ */
+ switch(conn->ip_version) {
+ case CURL_IPRESOLVE_V4:
+ pf = PF_INET;
+ break;
+ case CURL_IPRESOLVE_V6:
+ pf = PF_INET6;
+ break;
+ default:
+ pf = PF_UNSPEC;
+ break;
+ }
+
+ if((pf != PF_INET) && !Curl_ipv6works())
+ /* the stack seems to be a non-ipv6 one */
+ pf = PF_INET;
+
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = pf;
+ hints.ai_socktype = conn->socktype;
+
+ if((1 == Curl_inet_pton(AF_INET, hostname, addrbuf)) ||
+ (1 == Curl_inet_pton(AF_INET6, hostname, addrbuf))) {
+ /* the given address is numerical only, prevent a reverse lookup */
+ hints.ai_flags = AI_NUMERICHOST;
+ }
+
+ if(port) {
+ snprintf(sbuf, sizeof(sbuf), "%d", port);
+ sbufptr=sbuf;
+ }
+ error = Curl_getaddrinfo_ex(hostname, sbufptr, &hints, &res);
+ if(error) {
+ infof(data, "getaddrinfo(3) failed for %s:%d\n", hostname, port);
+ return NULL;
+ }
+
+ dump_addrinfo(conn, res);
+
+ return res;
+}
+#endif /* CURLRES_SYNCH */
+#endif /* CURLRES_IPV6 */
+
diff --git a/libs/libcurl/src/hostsyn.c b/libs/libcurl/src/hostsyn.c
new file mode 100644
index 0000000000..4ad3c63da4
--- /dev/null
+++ b/libs/libcurl/src/hostsyn.c
@@ -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 "curl_setup.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifdef HAVE_PROCESS_H
+#include <process.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "hash.h"
+#include "share.h"
+#include "strerror.h"
+#include "url.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"
+
+/***********************************************************************
+ * Only for builds using synchronous name resolves
+ **********************************************************************/
+#ifdef CURLRES_SYNCH
+
+/*
+ * Function provided by the resolver backend to set DNS servers to use.
+ */
+CURLcode Curl_set_dns_servers(struct SessionHandle *data,
+ char *servers)
+{
+ (void)data;
+ (void)servers;
+ return CURLE_NOT_BUILT_IN;
+
+}
+
+/*
+ * 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 */
diff --git a/libs/libcurl/src/http.c b/libs/libcurl/src/http.c
new file mode 100644
index 0000000000..a147181d5d
--- /dev/null
+++ b/libs/libcurl/src/http.c
@@ -0,0 +1,3527 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "formdata.h"
+#include "progress.h"
+#include "curl_base64.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "http_digest.h"
+#include "curl_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "http_negotiate.h"
+#include "url.h"
+#include "share.h"
+#include "hostip.h"
+#include "http.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "rawstr.h"
+#include "content_encoding.h"
+#include "http_proxy.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "bundles.h"
+#include "pipeline.h"
+#include "http2.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Forward declarations.
+ */
+
+static int http_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+static int http_should_fail(struct connectdata *conn);
+
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done);
+static int https_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+#else
+#define https_connecting(x,y) CURLE_COULDNT_CONNECT
+#endif
+
+/*
+ * HTTP handler interface.
+ */
+const struct Curl_handler Curl_handler_http = {
+ "HTTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTPS handler interface.
+ */
+const struct Curl_handler Curl_handler_https = {
+ "HTTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ Curl_http_connect, /* connect_it */
+ https_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ https_getsock, /* proto_getsock */
+ http_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_HTTPS, /* defport */
+ CURLPROTO_HTTP | CURLPROTO_HTTPS, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#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).
+ *
+ * Returns a pointer to the first matching header or NULL if none matched.
+ */
+char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader)
+{
+ struct curl_slist *head;
+ size_t thislen = strlen(thisheader);
+
+ for(head = data->set.headers; head; head=head->next) {
+ if(Curl_raw_nequal(head->data, thisheader, thislen))
+ return head->data;
+ }
+ return NULL;
+}
+
+/*
+ * Strip off leading and trailing whitespace from the value in the
+ * given HTTP header line and return a strdupped copy. Returns NULL in
+ * case of allocation failure. Returns an empty string if the header value
+ * consists entirely of whitespace.
+ */
+static char *copy_header_value(const char *h)
+{
+ const char *start;
+ const char *end;
+ char *value;
+ size_t len;
+
+ DEBUGASSERT(h);
+
+ /* Find the end of the header name */
+ while(*h && (*h != ':'))
+ ++h;
+
+ if(*h)
+ /* Skip over colon */
+ ++h;
+
+ /* Find the first non-space letter */
+ start = h;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* data is in the host encoding so
+ use '\r' and '\n' instead of 0x0d and 0x0a */
+ end = strchr(start, '\r');
+ if(!end)
+ end = strchr(start, '\n');
+ if(!end)
+ end = strchr(start, '\0');
+ if(!end)
+ return NULL;
+
+ /* skip all trailing space letters */
+ while((end > start) && ISSPACE(*end))
+ end--;
+
+ /* get length of the type */
+ len = end-start+1;
+
+ value = malloc(len + 1);
+ if(!value)
+ return NULL;
+
+ memcpy(value, start, len);
+ value[len] = 0; /* zero terminate */
+
+ return value;
+}
+
+/*
+ * http_output_basic() sets up an Authorization: header (or the proxy version)
+ * for HTTP Basic authentication.
+ *
+ * Returns CURLcode.
+ */
+static CURLcode http_output_basic(struct connectdata *conn, bool proxy)
+{
+ size_t size = 0;
+ char *authorization = NULL;
+ struct SessionHandle *data = conn->data;
+ char **userp;
+ const char *user;
+ const char *pwd;
+ CURLcode error;
+
+ if(proxy) {
+ userp = &conn->allocptr.proxyuserpwd;
+ user = conn->proxyuser;
+ pwd = conn->proxypasswd;
+ }
+ else {
+ userp = &conn->allocptr.userpwd;
+ user = conn->user;
+ pwd = conn->passwd;
+ }
+
+ snprintf(data->state.buffer, sizeof(data->state.buffer), "%s:%s", user, pwd);
+
+ error = Curl_base64_encode(data,
+ data->state.buffer, strlen(data->state.buffer),
+ &authorization, &size);
+ if(error)
+ return error;
+
+ if(!authorization)
+ return CURLE_REMOTE_ACCESS_DENIED;
+
+ Curl_safefree(*userp);
+ *userp = aprintf("%sAuthorization: Basic %s\r\n",
+ proxy?"Proxy-":"",
+ authorization);
+ free(authorization);
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+/* pickoneauth() selects the most favourable authentication method from the
+ * ones available and the ones we want.
+ *
+ * return TRUE if one was picked
+ */
+static bool pickoneauth(struct auth *pick)
+{
+ bool picked;
+ /* only deal with authentication we want */
+ unsigned long avail = pick->avail & pick->want;
+ picked = TRUE;
+
+ /* The order of these checks is highly relevant, as this will be the order
+ of preference in case of the existence of multiple accepted types. */
+ if(avail & CURLAUTH_GSSNEGOTIATE)
+ pick->picked = CURLAUTH_GSSNEGOTIATE;
+ else if(avail & CURLAUTH_DIGEST)
+ pick->picked = CURLAUTH_DIGEST;
+ else if(avail & CURLAUTH_NTLM)
+ pick->picked = CURLAUTH_NTLM;
+ else if(avail & CURLAUTH_NTLM_WB)
+ pick->picked = CURLAUTH_NTLM_WB;
+ else if(avail & CURLAUTH_BASIC)
+ pick->picked = CURLAUTH_BASIC;
+ else {
+ pick->picked = CURLAUTH_PICKNONE; /* we select to use nothing */
+ picked = FALSE;
+ }
+ pick->avail = CURLAUTH_NONE; /* clear it here */
+
+ return picked;
+}
+
+/*
+ * Curl_http_perhapsrewind()
+ *
+ * If we are doing POST or PUT {
+ * If we have more data to send {
+ * If we are doing NTLM {
+ * Keep sending since we must not disconnect
+ * }
+ * else {
+ * If there is more than just a little data left to send, close
+ * the current connection by force.
+ * }
+ * }
+ * If we have sent any data {
+ * If we don't have track of all the data {
+ * call app to tell it to rewind
+ * }
+ * else {
+ * rewind internally so that the operation can restart fine
+ * }
+ * }
+ * }
+ */
+static CURLcode http_perhapsrewind(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ struct HTTP *http = data->req.protop;
+ curl_off_t bytessent;
+ curl_off_t expectsend = -1; /* default is unknown */
+
+ if(!http)
+ /* If this is still NULL, we have not reach very far and we can safely
+ skip this rewinding stuff */
+ return CURLE_OK;
+
+ switch(data->set.httpreq) {
+ case HTTPREQ_GET:
+ case HTTPREQ_HEAD:
+ return CURLE_OK;
+ default:
+ break;
+ }
+
+ bytessent = http->writebytecount;
+
+ if(conn->bits.authneg)
+ /* This is a state where we are known to be negotiating and we don't send
+ any data then. */
+ expectsend = 0;
+ else {
+ /* figure out how much data we are expected to send */
+ switch(data->set.httpreq) {
+ case HTTPREQ_POST:
+ if(data->set.postfieldsize != -1)
+ expectsend = data->set.postfieldsize;
+ else if(data->set.postfields)
+ expectsend = (curl_off_t)strlen(data->set.postfields);
+ break;
+ case HTTPREQ_PUT:
+ if(data->set.infilesize != -1)
+ expectsend = data->set.infilesize;
+ break;
+ case HTTPREQ_POST_FORM:
+ expectsend = http->postsize;
+ break;
+ default:
+ break;
+ }
+ }
+
+ conn->bits.rewindaftersend = FALSE; /* default */
+
+ if((expectsend == -1) || (expectsend > bytessent)) {
+ /* There is still data left to send */
+ if((data->state.authproxy.picked == CURLAUTH_NTLM) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM) ||
+ (data->state.authproxy.picked == CURLAUTH_NTLM_WB) ||
+ (data->state.authhost.picked == CURLAUTH_NTLM_WB)) {
+ if(((expectsend - bytessent) < 2000) ||
+ (conn->ntlm.state != NTLMSTATE_NONE) ||
+ (conn->proxyntlm.state != NTLMSTATE_NONE)) {
+ /* The NTLM-negotiation has started *OR* there is just a little (<2K)
+ data left to send, keep on sending. */
+
+ /* rewind data when completely done sending! */
+ if(!conn->bits.authneg) {
+ conn->bits.rewindaftersend = TRUE;
+ infof(data, "Rewind stream after send\n");
+ }
+
+ return CURLE_OK;
+ }
+ if(conn->bits.close)
+ /* this is already marked to get closed */
+ return CURLE_OK;
+
+ infof(data, "NTLM send, close instead of sending %" FORMAT_OFF_T
+ " bytes\n", (curl_off_t)(expectsend - bytessent));
+ }
+
+ /* This is not NTLM or many bytes left to send: close
+ */
+ conn->bits.close = TRUE;
+ data->req.size = 0; /* don't download any more than 0 bytes */
+
+ /* There still is data left to send, but this connection is marked for
+ closure so we can safely do the rewind right now */
+ }
+
+ if(bytessent)
+ /* we rewind now at once since if we already sent something */
+ return Curl_readrewind(conn);
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_http_auth_act() gets called when all HTTP headers have been received
+ * and it checks what authentication methods that are available and decides
+ * which one (if any) to use. It will set 'newurl' if an auth method was
+ * picked.
+ */
+
+CURLcode Curl_http_auth_act(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ bool pickhost = FALSE;
+ bool pickproxy = FALSE;
+ CURLcode code = CURLE_OK;
+
+ if(100 <= data->req.httpcode && 199 >= data->req.httpcode)
+ /* this is a transient response code, ignore */
+ return CURLE_OK;
+
+ if(data->state.authproblem)
+ return data->set.http_fail_on_error?CURLE_HTTP_RETURNED_ERROR:CURLE_OK;
+
+ if(conn->bits.user_passwd &&
+ ((data->req.httpcode == 401) ||
+ (conn->bits.authneg && data->req.httpcode < 300))) {
+ pickhost = pickoneauth(&data->state.authhost);
+ if(!pickhost)
+ data->state.authproblem = TRUE;
+ }
+ if(conn->bits.proxy_user_passwd &&
+ ((data->req.httpcode == 407) ||
+ (conn->bits.authneg && data->req.httpcode < 300))) {
+ pickproxy = pickoneauth(&data->state.authproxy);
+ if(!pickproxy)
+ data->state.authproblem = TRUE;
+ }
+
+ if(pickhost || pickproxy) {
+ /* In case this is GSS auth, the newurl field is already allocated so
+ we must make sure to free it before allocating a new one. As figured
+ out in bug #2284386 */
+ Curl_safefree(data->req.newurl);
+ data->req.newurl = strdup(data->change.url); /* clone URL */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD) &&
+ !conn->bits.rewindaftersend) {
+ code = http_perhapsrewind(conn);
+ if(code)
+ return code;
+ }
+ }
+
+ else if((data->req.httpcode < 300) &&
+ (!data->state.authhost.done) &&
+ conn->bits.authneg) {
+ /* no (known) authentication available,
+ authentication is not "done" yet and
+ no authentication seems to be required and
+ we didn't try HEAD or GET */
+ if((data->set.httpreq != HTTPREQ_GET) &&
+ (data->set.httpreq != HTTPREQ_HEAD)) {
+ data->req.newurl = strdup(data->change.url); /* clone URL */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authhost.done = TRUE;
+ }
+ }
+ if(http_should_fail(conn)) {
+ failf (data, "The requested URL returned error: %d",
+ data->req.httpcode);
+ code = CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ return code;
+}
+
+
+/*
+ * Output the correct authentication header depending on the auth type
+ * and whether or not it is to a proxy.
+ */
+static CURLcode
+output_auth_headers(struct connectdata *conn,
+ struct auth *authstatus,
+ const char *request,
+ const char *path,
+ bool proxy)
+{
+ struct SessionHandle *data = conn->data;
+ const char *auth=NULL;
+ CURLcode result = CURLE_OK;
+#ifdef USE_HTTP_NEGOTIATE
+ struct negotiatedata *negdata = proxy?
+ &data->state.proxyneg:&data->state.negotiate;
+#endif
+
+#ifdef CURL_DISABLE_CRYPTO_AUTH
+ (void)request;
+ (void)path;
+#endif
+
+#ifdef USE_HTTP_NEGOTIATE
+ negdata->state = GSS_AUTHNONE;
+ if((authstatus->picked == CURLAUTH_GSSNEGOTIATE) &&
+ negdata->context && !GSS_ERROR(negdata->status)) {
+ auth="GSS-Negotiate";
+ result = Curl_output_negotiate(conn, proxy);
+ if(result)
+ return result;
+ authstatus->done = TRUE;
+ negdata->state = GSS_AUTHSENT;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if(authstatus->picked == CURLAUTH_NTLM) {
+ auth="NTLM";
+ result = Curl_output_ntlm(conn, proxy);
+ if(result)
+ return result;
+ }
+ else
+#endif
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ if(authstatus->picked == CURLAUTH_NTLM_WB) {
+ auth="NTLM_WB";
+ result = Curl_output_ntlm_wb(conn, proxy);
+ if(result)
+ return result;
+ }
+ else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(authstatus->picked == CURLAUTH_DIGEST) {
+ auth="Digest";
+ result = Curl_output_digest(conn,
+ proxy,
+ (const unsigned char *)request,
+ (const unsigned char *)path);
+ if(result)
+ return result;
+ }
+ else
+#endif
+ if(authstatus->picked == CURLAUTH_BASIC) {
+ /* Basic */
+ if((proxy && conn->bits.proxy_user_passwd &&
+ !Curl_checkheaders(data, "Proxy-authorization:")) ||
+ (!proxy && conn->bits.user_passwd &&
+ !Curl_checkheaders(data, "Authorization:"))) {
+ auth="Basic";
+ result = http_output_basic(conn, proxy);
+ if(result)
+ return result;
+ }
+ /* NOTE: this function should set 'done' TRUE, as the other auth
+ functions work that way */
+ authstatus->done = TRUE;
+ }
+
+ if(auth) {
+ infof(data, "%s auth using %s with user '%s'\n",
+ proxy?"Proxy":"Server", auth,
+ proxy?(conn->proxyuser?conn->proxyuser:""):
+ (conn->user?conn->user:""));
+ authstatus->multi = (!authstatus->done) ? TRUE : FALSE;
+ }
+ else
+ authstatus->multi = FALSE;
+
+ return CURLE_OK;
+}
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ const char *request,
+ const char *path,
+ bool proxytunnel) /* TRUE if this is the request setting
+ up the proxy tunnel */
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct auth *authhost;
+ struct auth *authproxy;
+
+ DEBUGASSERT(data);
+
+ authhost = &data->state.authhost;
+ authproxy = &data->state.authproxy;
+
+ if((conn->bits.httpproxy && conn->bits.proxy_user_passwd) ||
+ conn->bits.user_passwd)
+ /* continue please */ ;
+ else {
+ authhost->done = TRUE;
+ authproxy->done = TRUE;
+ return CURLE_OK; /* no authentication with no user or password */
+ }
+
+ if(authhost->want && !authhost->picked)
+ /* The app has selected one or more methods, but none has been picked
+ so far by a server round-trip. Then we set the picked one to the
+ want one, and if this is one single bit it'll be used instantly. */
+ authhost->picked = authhost->want;
+
+ if(authproxy->want && !authproxy->picked)
+ /* The app has selected one or more methods, but none has been picked so
+ far by a proxy round-trip. Then we set the picked one to the want one,
+ and if this is one single bit it'll be used instantly. */
+ authproxy->picked = authproxy->want;
+
+#ifndef CURL_DISABLE_PROXY
+ /* Send proxy authentication header if needed */
+ if(conn->bits.httpproxy &&
+ (conn->bits.tunnel_proxy == proxytunnel)) {
+ result = output_auth_headers(conn, authproxy, request, path, TRUE);
+ if(result)
+ return result;
+ }
+ else
+#else
+ (void)proxytunnel;
+#endif /* CURL_DISABLE_PROXY */
+ /* we have no proxy so let's pretend we're done authenticating
+ with it */
+ authproxy->done = TRUE;
+
+ /* To prevent the user+password to get sent to other than the original
+ host due to a location-follow, we do some weirdo checks here */
+ if(!data->state.this_is_a_follow ||
+ conn->bits.netrc ||
+ !data->state.first_host ||
+ data->set.http_disable_hostname_check_before_authentication ||
+ Curl_raw_equal(data->state.first_host, conn->host.name)) {
+ result = output_auth_headers(conn, authhost, request, path, FALSE);
+ }
+ else
+ authhost->done = TRUE;
+
+ return result;
+}
+
+
+/*
+ * Curl_http_input_auth() deals with Proxy-Authenticate: and WWW-Authenticate:
+ * headers. They are dealt with both in the transfer.c main loop and in the
+ * proxy CONNECT loop.
+ */
+
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+ int httpcode,
+ const char *header) /* the first non-space */
+{
+ /*
+ * This resource requires authentication
+ */
+ struct SessionHandle *data = conn->data;
+
+ unsigned long *availp;
+ const char *start;
+ struct auth *authp;
+
+ if(httpcode == 407) {
+ start = header+strlen("Proxy-authenticate:");
+ availp = &data->info.proxyauthavail;
+ authp = &data->state.authproxy;
+ }
+ else {
+ start = header+strlen("WWW-Authenticate:");
+ availp = &data->info.httpauthavail;
+ authp = &data->state.authhost;
+ }
+
+ /* pass all white spaces */
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /*
+ * Here we check if we want the specific single authentication (using ==) and
+ * if we do, we initiate usage of it.
+ *
+ * If the provided authentication is wanted as one out of several accepted
+ * types (using &), we OR this authentication type to the authavail
+ * variable.
+ *
+ * Note:
+ *
+ * ->picked is first set to the 'want' value (one or more bits) before the
+ * request is sent, and then it is again set _after_ all response 401/407
+ * headers have been received but then only to a single preferred method
+ * (bit).
+ *
+ */
+
+ while(*start) {
+#ifdef USE_HTTP_NEGOTIATE
+ if(checkprefix("GSS-Negotiate", start) ||
+ checkprefix("Negotiate", start)) {
+ int neg;
+ *availp |= CURLAUTH_GSSNEGOTIATE;
+ authp->avail |= CURLAUTH_GSSNEGOTIATE;
+
+ if(authp->picked == CURLAUTH_GSSNEGOTIATE) {
+ if(data->state.negotiate.state == GSS_AUTHSENT) {
+ /* if we sent GSS authentication in the outgoing request and we get
+ this back, we're in trouble */
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ else {
+ neg = Curl_input_negotiate(conn, (bool)(httpcode == 407), start);
+ if(neg == 0) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->change.url);
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+ data->state.authproblem = FALSE;
+ /* we received GSS auth info and we dealt with it fine */
+ data->state.negotiate.state = GSS_AUTHRECV;
+ }
+ else
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ /* NTLM support requires the SSL crypto libs */
+ if(checkprefix("NTLM", start)) {
+ *availp |= CURLAUTH_NTLM;
+ authp->avail |= CURLAUTH_NTLM;
+ if(authp->picked == CURLAUTH_NTLM ||
+ authp->picked == CURLAUTH_NTLM_WB) {
+ /* NTLM authentication is picked and activated */
+ CURLcode ntlm =
+ Curl_input_ntlm(conn, (httpcode == 407)?TRUE:FALSE, start);
+ if(CURLE_OK == ntlm) {
+ data->state.authproblem = FALSE;
+#ifdef NTLM_WB_ENABLED
+ if(authp->picked == CURLAUTH_NTLM_WB) {
+ *availp &= ~CURLAUTH_NTLM;
+ authp->avail &= ~CURLAUTH_NTLM;
+ *availp |= CURLAUTH_NTLM_WB;
+ authp->avail |= CURLAUTH_NTLM_WB;
+
+ /* Get the challenge-message which will be passed to
+ * ntlm_auth for generating the type 3 message later */
+ while(*start && ISSPACE(*start))
+ start++;
+ if(checkprefix("NTLM", start)) {
+ start += strlen("NTLM");
+ while(*start && ISSPACE(*start))
+ start++;
+ if(*start)
+ if((conn->challenge_header = strdup(start)) == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+#endif
+ }
+ else {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if(checkprefix("Digest", start)) {
+ if((authp->avail & CURLAUTH_DIGEST) != 0) {
+ infof(data, "Ignoring duplicate digest auth header.\n");
+ }
+ else {
+ CURLdigest dig;
+ *availp |= CURLAUTH_DIGEST;
+ authp->avail |= CURLAUTH_DIGEST;
+
+ /* We call this function on input Digest headers even if Digest
+ * authentication isn't activated yet, as we need to store the
+ * incoming data from this header in case we are gonna use
+ * Digest. */
+ dig = Curl_input_digest(conn, (httpcode == 407)?TRUE:FALSE, start);
+
+ if(CURLDIGEST_FINE != dig) {
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+ }
+ else
+#endif
+ if(checkprefix("Basic", start)) {
+ *availp |= CURLAUTH_BASIC;
+ authp->avail |= CURLAUTH_BASIC;
+ if(authp->picked == CURLAUTH_BASIC) {
+ /* We asked for Basic authentication but got a 40X back
+ anyway, which basically means our name+password isn't
+ valid. */
+ authp->avail = CURLAUTH_NONE;
+ infof(data, "Authentication problem. Ignoring this.\n");
+ data->state.authproblem = TRUE;
+ }
+ }
+
+ /* there may be multiple methods on one line, so keep reading */
+ while(*start && *start != ',') /* read up to the next comma */
+ start++;
+ if(*start == ',') /* if we're on a comma, skip it */
+ start++;
+ while(*start && ISSPACE(*start))
+ start++;
+ }
+ return CURLE_OK;
+}
+
+/**
+ * http_should_fail() determines whether an HTTP response has gotten us
+ * into an error state or not.
+ *
+ * @param conn all information about the current connection
+ *
+ * @retval 0 communications should continue
+ *
+ * @retval 1 communications should not continue
+ */
+static int http_should_fail(struct connectdata *conn)
+{
+ struct SessionHandle *data;
+ int httpcode;
+
+ DEBUGASSERT(conn);
+ data = conn->data;
+ DEBUGASSERT(data);
+
+ httpcode = data->req.httpcode;
+
+ /*
+ ** If we haven't been asked to fail on error,
+ ** don't fail.
+ */
+ if(!data->set.http_fail_on_error)
+ return 0;
+
+ /*
+ ** Any code < 400 is never terminal.
+ */
+ if(httpcode < 400)
+ return 0;
+
+ if(data->state.resume_from &&
+ (data->set.httpreq==HTTPREQ_GET) &&
+ (httpcode == 416)) {
+ /* "Requested Range Not Satisfiable", just proceed and
+ pretend this is no error */
+ return 0;
+ }
+
+ /*
+ ** Any code >= 400 that's not 401 or 407 is always
+ ** a terminal error
+ */
+ if((httpcode != 401) &&
+ (httpcode != 407))
+ return 1;
+
+ /*
+ ** All we have left to deal with is 401 and 407
+ */
+ DEBUGASSERT((httpcode == 401) || (httpcode == 407));
+
+ /*
+ ** Examine the current authentication state to see if this
+ ** is an error. The idea is for this function to get
+ ** called after processing all the headers in a response
+ ** message. So, if we've been to asked to authenticate a
+ ** particular stage, and we've done it, we're OK. But, if
+ ** we're already completely authenticated, it's not OK to
+ ** get another 401 or 407.
+ **
+ ** It is possible for authentication to go stale such that
+ ** the client needs to reauthenticate. Once that info is
+ ** available, use it here.
+ */
+
+ /*
+ ** Either we're not authenticating, or we're supposed to
+ ** be authenticating something else. This is an error.
+ */
+ if((httpcode == 401) && !conn->bits.user_passwd)
+ return TRUE;
+ if((httpcode == 407) && !conn->bits.proxy_user_passwd)
+ return TRUE;
+
+ return data->state.authproblem;
+}
+
+/*
+ * readmoredata() is a "fread() emulation" to provide POST and/or request
+ * data. It is used when a huge POST is to be made and the entire chunk wasn't
+ * sent in the first send(). This function will then be called from the
+ * transfer.c loop when more data is to be sent to the peer.
+ *
+ * Returns the amount of bytes it filled the buffer with.
+ */
+static size_t readmoredata(char *buffer,
+ size_t size,
+ size_t nitems,
+ void *userp)
+{
+ struct connectdata *conn = (struct connectdata *)userp;
+ struct HTTP *http = conn->data->req.protop;
+ size_t fullsize = size * nitems;
+
+ if(0 == http->postsize)
+ /* nothing to return */
+ return 0;
+
+ /* make sure that a HTTP request is never sent away chunked! */
+ conn->data->req.forbidchunk = (http->sending == HTTPSEND_REQUEST)?TRUE:FALSE;
+
+ if(http->postsize <= (curl_off_t)fullsize) {
+ memcpy(buffer, http->postdata, (size_t)http->postsize);
+ fullsize = (size_t)http->postsize;
+
+ if(http->backup.postsize) {
+ /* move backup data into focus and continue on that */
+ http->postdata = http->backup.postdata;
+ http->postsize = http->backup.postsize;
+ conn->fread_func = http->backup.fread_func;
+ conn->fread_in = http->backup.fread_in;
+
+ http->sending++; /* move one step up */
+
+ http->backup.postsize=0;
+ }
+ else
+ http->postsize = 0;
+
+ return fullsize;
+ }
+
+ memcpy(buffer, http->postdata, fullsize);
+ http->postdata += fullsize;
+ http->postsize -= fullsize;
+
+ return fullsize;
+}
+
+/* ------------------------------------------------------------------------- */
+/* add_buffer functions */
+
+/*
+ * Curl_add_buffer_init() sets up and returns a fine buffer struct
+ */
+Curl_send_buffer *Curl_add_buffer_init(void)
+{
+ return calloc(1, sizeof(Curl_send_buffer));
+}
+
+/*
+ * Curl_add_buffer_send() sends a header buffer and frees all associated
+ * memory. Body data may be appended to the header data if desired.
+ *
+ * Returns CURLcode
+ */
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+ struct connectdata *conn,
+
+ /* add the number of sent bytes to this
+ counter */
+ long *bytes_written,
+
+ /* how much of the buffer contains body data */
+ size_t included_body_bytes,
+ int socketindex)
+
+{
+ ssize_t amount;
+ CURLcode res;
+ char *ptr;
+ size_t size;
+ struct HTTP *http = conn->data->req.protop;
+ size_t sendsize;
+ curl_socket_t sockfd;
+ size_t headersize;
+
+ DEBUGASSERT(socketindex <= SECONDARYSOCKET);
+
+ sockfd = conn->sock[socketindex];
+
+ /* The looping below is required since we use non-blocking sockets, but due
+ to the circumstances we will just loop and try again and again etc */
+
+ ptr = in->buffer;
+ size = in->size_used;
+
+ headersize = size - included_body_bytes; /* the initial part that isn't body
+ is header */
+
+ DEBUGASSERT(size > included_body_bytes);
+
+ res = Curl_convert_to_network(conn->data, ptr, headersize);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(res) {
+ /* conversion failed, free memory and return to the caller */
+ if(in->buffer)
+ free(in->buffer);
+ free(in);
+ return res;
+ }
+
+ if(conn->handler->flags & PROTOPT_SSL) {
+ /* We never send more than CURL_MAX_WRITE_SIZE bytes in one single chunk
+ when we speak HTTPS, as if only a fraction of it is sent now, this data
+ needs to fit into the normal read-callback buffer later on and that
+ buffer is using this size.
+ */
+
+ sendsize= (size > CURL_MAX_WRITE_SIZE)?CURL_MAX_WRITE_SIZE:size;
+
+ /* OpenSSL is very picky and we must send the SAME buffer pointer to the
+ library when we attempt to re-send this buffer. Sending the same data
+ is not enough, we must use the exact same address. For this reason, we
+ must copy the data to the uploadbuffer first, since that is the buffer
+ we will be using if this send is retried later.
+ */
+ memcpy(conn->data->state.uploadbuffer, ptr, sendsize);
+ ptr = conn->data->state.uploadbuffer;
+ }
+ else
+ sendsize = size;
+
+ res = Curl_write(conn, sockfd, ptr, sendsize, &amount);
+
+ if(CURLE_OK == res) {
+ /*
+ * Note that we may not send the entire chunk at once, and we have a set
+ * number of data bytes at the end of the big buffer (out of which we may
+ * only send away a part).
+ */
+ /* how much of the header that was sent */
+ size_t headlen = (size_t)amount>headersize?headersize:(size_t)amount;
+ size_t bodylen = amount - headlen;
+
+ if(conn->data->set.verbose) {
+ /* this data _may_ contain binary stuff */
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT, ptr, headlen, conn);
+ if(bodylen) {
+ /* there was body data sent beyond the initial header part, pass that
+ on to the debug callback too */
+ Curl_debug(conn->data, CURLINFO_DATA_OUT,
+ ptr+headlen, bodylen, conn);
+ }
+ }
+
+ /* 'amount' can never be a very large value here so typecasting it so a
+ signed 31 bit value should not cause problems even if ssize_t is
+ 64bit */
+ *bytes_written += (long)amount;
+
+ if(http) {
+ if(bodylen)
+ /* since we sent a piece of the body here, up the byte counter for it
+ accordingly */
+ http->writebytecount += bodylen;
+ if((size_t)amount != size) {
+ /* The whole request could not be sent in one system call. We must
+ queue it up and send it later when we get the chance. We must not
+ loop here and wait until it might work again. */
+
+ size -= amount;
+
+ ptr = in->buffer + amount;
+
+ /* backup the currently set pointers */
+ http->backup.fread_func = conn->fread_func;
+ http->backup.fread_in = conn->fread_in;
+ http->backup.postdata = http->postdata;
+ http->backup.postsize = http->postsize;
+
+ /* set the new pointers for the request-sending */
+ conn->fread_func = (curl_read_callback)readmoredata;
+ conn->fread_in = (void *)conn;
+ http->postdata = ptr;
+ http->postsize = (curl_off_t)size;
+
+ http->send_buffer = in;
+ http->sending = HTTPSEND_REQUEST;
+
+ return CURLE_OK;
+ }
+ http->sending = HTTPSEND_BODY;
+ /* the full buffer was sent, clean up and return */
+ }
+ else {
+ if((size_t)amount != size)
+ /* We have no continue-send mechanism now, fail. This can only happen
+ when this function is used from the CONNECT sending function. We
+ currently (stupidly) assume that the whole request is always sent
+ away in the first single chunk.
+
+ This needs FIXing.
+ */
+ return CURLE_SEND_ERROR;
+ else
+ conn->writechannel_inuse = FALSE;
+ }
+ }
+ if(in->buffer)
+ free(in->buffer);
+ free(in);
+
+ return res;
+}
+
+
+/*
+ * add_bufferf() add the formatted input to the buffer.
+ */
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...)
+{
+ char *s;
+ va_list ap;
+ va_start(ap, fmt);
+ s = vaprintf(fmt, ap); /* this allocs a new string to append */
+ va_end(ap);
+
+ if(s) {
+ CURLcode result = Curl_add_buffer(in, s, strlen(s));
+ free(s);
+ return result;
+ }
+ /* If we failed, we cleanup the whole buffer and return error */
+ if(in->buffer)
+ free(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+}
+
+/*
+ * add_buffer() appends a memory chunk to the existing buffer
+ */
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size)
+{
+ char *new_rb;
+ size_t new_size;
+
+ if(~size < in->size_used) {
+ /* If resulting used size of send buffer would wrap size_t, cleanup
+ the whole buffer and return error. Otherwise the required buffer
+ size will fit into a single allocatable memory chunk */
+ Curl_safefree(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!in->buffer ||
+ ((in->size_used + size) > (in->size_max - 1))) {
+
+ /* If current buffer size isn't enough to hold the result, use a
+ buffer size that doubles the required size. If this new size
+ would wrap size_t, then just use the largest possible one */
+
+ if((size > (size_t)-1/2) || (in->size_used > (size_t)-1/2) ||
+ (~(size*2) < (in->size_used*2)))
+ new_size = (size_t)-1;
+ else
+ new_size = (in->size_used+size)*2;
+
+ if(in->buffer)
+ /* we have a buffer, enlarge the existing one */
+ new_rb = realloc(in->buffer, new_size);
+ else
+ /* create a new buffer */
+ new_rb = malloc(new_size);
+
+ if(!new_rb) {
+ /* If we failed, we cleanup the whole buffer and return error */
+ Curl_safefree(in->buffer);
+ free(in);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ in->buffer = new_rb;
+ in->size_max = new_size;
+ }
+ memcpy(&in->buffer[in->size_used], inptr, size);
+
+ in->size_used += size;
+
+ return CURLE_OK;
+}
+
+/* end of the add_buffer functions */
+/* ------------------------------------------------------------------------- */
+
+
+
+/*
+ * Curl_compareheader()
+ *
+ * Returns TRUE if 'headerline' contains the 'header' with given 'content'.
+ * Pass headers WITH the colon.
+ */
+bool
+Curl_compareheader(const char *headerline, /* line to check */
+ const char *header, /* header keyword _with_ colon */
+ const char *content) /* content string to find */
+{
+ /* RFC2616, section 4.2 says: "Each header field consists of a name followed
+ * by a colon (":") and the field value. Field names are case-insensitive.
+ * The field value MAY be preceded by any amount of LWS, though a single SP
+ * is preferred." */
+
+ size_t hlen = strlen(header);
+ size_t clen;
+ size_t len;
+ const char *start;
+ const char *end;
+
+ if(!Curl_raw_nequal(headerline, header, hlen))
+ return FALSE; /* doesn't start with header */
+
+ /* pass the header */
+ start = &headerline[hlen];
+
+ /* pass all white spaces */
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* find the end of the header line */
+ end = strchr(start, '\r'); /* lines end with CRLF */
+ if(!end) {
+ /* in case there's a non-standard compliant line here */
+ end = strchr(start, '\n');
+
+ if(!end)
+ /* hm, there's no line ending here, use the zero byte! */
+ end = strchr(start, '\0');
+ }
+
+ len = end-start; /* length of the content part of the input line */
+ clen = strlen(content); /* length of the word to find */
+
+ /* find the content string in the rest of the line */
+ for(;len>=clen;len--, start++) {
+ if(Curl_raw_nequal(start, content, clen))
+ return TRUE; /* match! */
+ }
+
+ return FALSE; /* no match */
+}
+
+/*
+ * Curl_http_connect() performs HTTP stuff to do at connect-time, called from
+ * the generic Curl_connect().
+ */
+CURLcode Curl_http_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+
+ /* We default to persistent connections. We set this already in this connect
+ function to make the re-use checks properly be able to check this bit. */
+ conn->bits.close = FALSE;
+
+ /* the CONNECT procedure might not have been completed */
+ result = Curl_proxy_connect(conn);
+ if(result)
+ return result;
+
+ if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ /* nothing else to do except wait right now - we're not done here. */
+ return CURLE_OK;
+
+ if(conn->given->flags & PROTOPT_SSL) {
+ /* perform SSL initialization */
+ result = https_connecting(conn, done);
+ if(result)
+ return result;
+ }
+ else
+ *done = TRUE;
+
+ return CURLE_OK;
+}
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+ interface and then we're always _sending_ a request and thus we wait for
+ the single socket to become writable only */
+static int http_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ /* write mode */
+ (void)numsocks; /* unused, we trust it to be at least 1 */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+}
+
+#ifdef USE_SSL
+static CURLcode https_connecting(struct connectdata *conn, bool *done)
+{
+ CURLcode result;
+ DEBUGASSERT((conn) && (conn->handler->flags & PROTOPT_SSL));
+
+ /* perform SSL initialization for this socket */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, done);
+ if(result)
+ conn->bits.close = TRUE; /* a failed connection is marked for closure
+ to prevent (bad) re-use or similar */
+ return result;
+}
+#endif
+
+#if defined(USE_SSLEAY) || defined(USE_GNUTLS) || defined(USE_SCHANNEL) || \
+ defined(USE_DARWINSSL)
+/* This function is for OpenSSL, GnuTLS, darwinssl, and schannel only.
+ It should be made to query the generic SSL layer instead. */
+static int https_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn->handler->flags & PROTOPT_SSL) {
+ struct ssl_connect_data *connssl = &conn->ssl[FIRSTSOCKET];
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ if(connssl->connecting_state == ssl_connect_2_writing) {
+ /* write mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+ }
+ else if(connssl->connecting_state == ssl_connect_2_reading) {
+ /* read mode */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_READSOCK(0);
+ }
+ }
+ return CURLE_OK;
+}
+#else
+#ifdef USE_SSL
+static int https_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ (void)conn;
+ (void)socks;
+ (void)numsocks;
+ return GETSOCK_BLANK;
+}
+#endif /* USE_SSL */
+#endif /* USE_SSLEAY || USE_GNUTLS || USE_SCHANNEL */
+
+/*
+ * Curl_http_done() gets called from Curl_done() after a single HTTP request
+ * has been performed.
+ */
+
+CURLcode Curl_http_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct SessionHandle *data = conn->data;
+ struct HTTP *http =data->req.protop;
+
+ Curl_unencode_cleanup(conn);
+
+ /* set the proper values (possibly modified on POST) */
+ conn->fread_func = data->set.fread_func; /* restore */
+ conn->fread_in = data->set.in; /* restore */
+ conn->seek_func = data->set.seek_func; /* restore */
+ conn->seek_client = data->set.seek_client; /* restore */
+
+ if(http == NULL)
+ return CURLE_OK;
+
+ if(http->send_buffer) {
+ Curl_send_buffer *buff = http->send_buffer;
+
+ free(buff->buffer);
+ free(buff);
+ http->send_buffer = NULL; /* clear the pointer */
+ }
+
+ if(HTTPREQ_POST_FORM == data->set.httpreq) {
+ data->req.bytecount = http->readbytecount + http->writebytecount;
+
+ Curl_formclean(&http->sendit); /* Now free that whole lot */
+ if(http->form.fp) {
+ /* a file being uploaded was left opened, close it! */
+ fclose(http->form.fp);
+ http->form.fp = NULL;
+ }
+ }
+ else if(HTTPREQ_PUT == data->set.httpreq)
+ data->req.bytecount = http->readbytecount + http->writebytecount;
+
+ if(status != CURLE_OK)
+ return (status);
+
+ 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) {
+ /* If this connection isn't simply closed to be retried, AND nothing was
+ read from the HTTP server (that counts), this can't be right so we
+ return an error here */
+ failf(data, "Empty reply from server");
+ return CURLE_GOT_NOTHING;
+ }
+
+ return CURLE_OK;
+}
+
+
+/*
+ * 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) ||
+ ((data->set.httpversion != CURL_HTTP_VERSION_1_0) &&
+ ((conn->httpversion == 11) ||
+ ((conn->httpversion != 10) &&
+ (data->state.httpversion != 10))))) ? TRUE : FALSE;
+}
+
+/* check and possibly add an Expect: header */
+static CURLcode expect100(struct SessionHandle *data,
+ struct connectdata *conn,
+ Curl_send_buffer *req_buffer)
+{
+ CURLcode result = CURLE_OK;
+ const char *ptr;
+ data->state.expect100header = FALSE; /* default to false unless it is set
+ to TRUE below */
+ 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) */
+ ptr = Curl_checkheaders(data, "Expect:");
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, "Expect:", "100-continue");
+ }
+ else {
+ result = Curl_add_bufferf(req_buffer,
+ "Expect: 100-continue\r\n");
+ if(result == CURLE_OK)
+ data->state.expect100header = TRUE;
+ }
+ }
+ return result;
+}
+
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+ Curl_send_buffer *req_buffer)
+{
+ char *ptr;
+ struct curl_slist *headers=conn->data->set.headers;
+
+ while(headers) {
+ ptr = strchr(headers->data, ':');
+ if(ptr) {
+ /* we require a colon for this to be a true header */
+
+ ptr++; /* pass the colon */
+ while(*ptr && ISSPACE(*ptr))
+ ptr++;
+
+ if(*ptr) {
+ /* only send this if the contents was non-blank */
+
+ if(conn->allocptr.host &&
+ /* a Host: header was sent already, don't pass on any custom Host:
+ header as that will produce *two* in the same request! */
+ checkprefix("Host:", headers->data))
+ ;
+ else if(conn->data->set.httpreq == HTTPREQ_POST_FORM &&
+ /* this header (extended by formdata.c) is sent later */
+ checkprefix("Content-Type:", headers->data))
+ ;
+ else if(conn->bits.authneg &&
+ /* while doing auth neg, don't allow the custom length since
+ we will force length zero then */
+ checkprefix("Content-Length", headers->data))
+ ;
+ else if(conn->allocptr.te &&
+ /* when asking for Transfer-Encoding, don't pass on a custom
+ Connection: */
+ checkprefix("Connection", headers->data))
+ ;
+ else {
+ CURLcode result = Curl_add_bufferf(req_buffer, "%s\r\n",
+ headers->data);
+ if(result)
+ return result;
+ }
+ }
+ }
+ else {
+ ptr = strchr(headers->data, ';');
+ if(ptr) {
+
+ ptr++; /* pass the semicolon */
+ while(*ptr && ISSPACE(*ptr))
+ ptr++;
+
+ if(*ptr) {
+ /* this may be used for something else in the future */
+ }
+ else {
+ if(*(--ptr) == ';') {
+ CURLcode result;
+
+ /* send no-value custom header if terminated by semicolon */
+ *ptr = ':';
+ result = Curl_add_bufferf(req_buffer, "%s\r\n",
+ headers->data);
+ if(result)
+ return result;
+ }
+ }
+ }
+ }
+ headers = headers->next;
+ }
+ return CURLE_OK;
+}
+
+CURLcode Curl_add_timecondition(struct SessionHandle *data,
+ Curl_send_buffer *req_buffer)
+{
+ const struct tm *tm;
+ char *buf = data->state.buffer;
+ CURLcode result = CURLE_OK;
+ struct tm keeptime;
+
+ result = Curl_gmtime(data->set.timevalue, &keeptime);
+ if(result) {
+ failf(data, "Invalid TIMEVALUE");
+ return result;
+ }
+ tm = &keeptime;
+
+ /* The If-Modified-Since header family should have their times set in
+ * GMT as RFC2616 defines: "All HTTP date/time stamps MUST be
+ * represented in Greenwich Mean Time (GMT), without exception. For the
+ * purposes of HTTP, GMT is exactly equal to UTC (Coordinated Universal
+ * Time)." (see page 20 of RFC2616).
+ */
+
+ /* format: "Tue, 15 Nov 1994 12:45:26 GMT" */
+ snprintf(buf, BUFSIZE-1,
+ "%s, %02d %s %4d %02d:%02d:%02d GMT",
+ Curl_wkday[tm->tm_wday?tm->tm_wday-1:6],
+ tm->tm_mday,
+ Curl_month[tm->tm_mon],
+ tm->tm_year + 1900,
+ tm->tm_hour,
+ tm->tm_min,
+ tm->tm_sec);
+
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ result = Curl_add_bufferf(req_buffer,
+ "If-Modified-Since: %s\r\n", buf);
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ result = Curl_add_bufferf(req_buffer,
+ "If-Unmodified-Since: %s\r\n", buf);
+ break;
+ case CURL_TIMECOND_LASTMOD:
+ result = Curl_add_bufferf(req_buffer,
+ "Last-Modified: %s\r\n", buf);
+ break;
+ }
+
+ return result;
+}
+
+/*
+ * Curl_http() gets called from the generic Curl_do() function when a HTTP
+ * request is to be performed. This creates and sends a properly constructed
+ * HTTP request.
+ */
+CURLcode Curl_http(struct connectdata *conn, bool *done)
+{
+ struct SessionHandle *data=conn->data;
+ CURLcode result=CURLE_OK;
+ struct HTTP *http;
+ const char *ppath = data->state.path;
+ bool paste_ftp_userpwd = FALSE;
+ char ftp_typecode[sizeof("/;type=?")] = "";
+ const char *host = conn->host.name;
+ const char *te = ""; /* transfer-encoding */
+ const char *ptr;
+ const char *request;
+ Curl_HttpReq httpreq = data->set.httpreq;
+ char *addcookies = NULL;
+ curl_off_t included_body = 0;
+ const char *httpstring;
+ Curl_send_buffer *req_buffer;
+ curl_off_t postsize = 0; /* curl_off_t to handle large file sizes */
+ int seekerr = CURL_SEEKFUNC_OK;
+
+ /* Always consider the DO phase done after this function call, even if there
+ may be parts of the request that is not yet sent, since we can deal with
+ the rest of the request in the PERFORM phase. */
+ *done = TRUE;
+
+ http = data->req.protop;
+
+ if(!data->state.this_is_a_follow) {
+ /* this is not a followed location, get the original host name */
+ if(data->state.first_host)
+ /* Free to avoid leaking memory on multiple requests*/
+ free(data->state.first_host);
+
+ data->state.first_host = strdup(conn->host.name);
+ if(!data->state.first_host)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ http->writebytecount = http->readbytecount = 0;
+
+ if((conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_FTP)) &&
+ data->set.upload) {
+ httpreq = HTTPREQ_PUT;
+ }
+
+ /* Now set the 'request' pointer to the proper request string */
+ if(data->set.str[STRING_CUSTOMREQUEST])
+ request = data->set.str[STRING_CUSTOMREQUEST];
+ else {
+ if(data->set.opt_no_body)
+ request = "HEAD";
+ else {
+ DEBUGASSERT((httpreq > HTTPREQ_NONE) && (httpreq < HTTPREQ_LAST));
+ switch(httpreq) {
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ request = "POST";
+ break;
+ case HTTPREQ_PUT:
+ request = "PUT";
+ break;
+ default: /* this should never happen */
+ case HTTPREQ_GET:
+ request = "GET";
+ break;
+ case HTTPREQ_HEAD:
+ request = "HEAD";
+ break;
+ }
+ }
+ }
+
+ /* The User-Agent string might have been allocated in url.c already, because
+ it might have been used in the proxy connect, but if we have got a header
+ with the user-agent string specified, we erase the previously made string
+ here. */
+ if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+ free(conn->allocptr.uagent);
+ conn->allocptr.uagent=NULL;
+ }
+
+ /* setup the authentication headers */
+ result = Curl_http_output_auth(conn, request, ppath, FALSE);
+ if(result)
+ return result;
+
+ if((data->state.authhost.multi || data->state.authproxy.multi) &&
+ (httpreq != HTTPREQ_GET) &&
+ (httpreq != HTTPREQ_HEAD)) {
+ /* Auth is required and we are not authenticated yet. Make a PUT or POST
+ with content-length zero as a "probe". */
+ conn->bits.authneg = TRUE;
+ }
+ else
+ conn->bits.authneg = FALSE;
+
+ Curl_safefree(conn->allocptr.ref);
+ if(data->change.referer && !Curl_checkheaders(data, "Referer:")) {
+ conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ if(!conn->allocptr.ref)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else
+ conn->allocptr.ref = NULL;
+
+ if(data->set.str[STRING_COOKIE] && !Curl_checkheaders(data, "Cookie:"))
+ addcookies = data->set.str[STRING_COOKIE];
+
+ if(!Curl_checkheaders(data, "Accept-Encoding:") &&
+ data->set.str[STRING_ENCODING]) {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding =
+ aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+ if(!conn->allocptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifdef HAVE_LIBZ
+ /* we only consider transfer-encoding magic if libz support is built-in */
+
+ if(!Curl_checkheaders(data, "TE:") && data->set.http_transfer_encoding) {
+ /* When we are to insert a TE: header in the request, we must also insert
+ TE in a Connection: header, so we need to merge the custom provided
+ Connection: header and prevent the original to get sent. Note that if
+ the user has inserted his/hers own TE: header we don't do this magic
+ but then assume that the user will handle it all! */
+ char *cptr = Curl_checkheaders(data, "Connection:");
+#define TE_HEADER "TE: gzip\r\n"
+
+ Curl_safefree(conn->allocptr.te);
+
+ /* Create the (updated) Connection: header */
+ conn->allocptr.te = cptr? aprintf("%s, TE\r\n" TE_HEADER, cptr):
+ strdup("Connection: TE\r\n" TE_HEADER);
+
+ if(!conn->allocptr.te)
+ return CURLE_OUT_OF_MEMORY;
+ }
+#endif
+
+ ptr = Curl_checkheaders(data, "Transfer-Encoding:");
+ if(ptr) {
+ /* Some kind of TE is requested, check if 'chunked' is chosen */
+ data->req.upload_chunky =
+ Curl_compareheader(ptr, "Transfer-Encoding:", "chunked");
+ }
+ else {
+ if((conn->handler->protocol&CURLPROTO_HTTP) &&
+ data->set.upload &&
+ (data->set.infilesize == -1)) {
+ if(conn->bits.authneg)
+ /* don't enable chunked during auth neg */
+ ;
+ else if(use_http_1_1plus(data, conn)) {
+ /* HTTP, upload, unknown file size and not HTTP 1.0 */
+ data->req.upload_chunky = TRUE;
+ }
+ else {
+ failf(data, "Chunky upload is not supported by HTTP 1.0");
+ return CURLE_UPLOAD_FAILED;
+ }
+ }
+ else {
+ /* else, no chunky upload */
+ data->req.upload_chunky = FALSE;
+ }
+
+ if(data->req.upload_chunky)
+ te = "Transfer-Encoding: chunked\r\n";
+ }
+
+ Curl_safefree(conn->allocptr.host);
+
+ ptr = Curl_checkheaders(data, "Host:");
+ if(ptr && (!data->state.this_is_a_follow ||
+ Curl_raw_equal(data->state.first_host, conn->host.name))) {
+#if !defined(CURL_DISABLE_COOKIES)
+ /* If we have a given custom Host: header, we extract the host name in
+ order to possibly use it for cookie reasons later on. We only allow the
+ custom Host: header if this is NOT a redirect, as setting Host: in the
+ redirected request is being out on thin ice. Except if the host name
+ is the same as the first one! */
+ char *cookiehost = copy_header_value(ptr);
+ if(!cookiehost)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*cookiehost)
+ /* ignore empty data */
+ free(cookiehost);
+ else {
+ /* If the host begins with '[', we start searching for the port after
+ the bracket has been closed */
+ int startsearch = 0;
+ if(*cookiehost == '[') {
+ char *closingbracket;
+ /* since the 'cookiehost' is an allocated memory area that will be
+ freed later we cannot simply increment the pointer */
+ memmove(cookiehost, cookiehost + 1, strlen(cookiehost) - 1);
+ closingbracket = strchr(cookiehost, ']');
+ if(closingbracket)
+ *closingbracket = 0;
+ }
+ else {
+ char *colon = strchr(cookiehost + startsearch, ':');
+ if(colon)
+ *colon = 0; /* The host must not include an embedded port number */
+ }
+ Curl_safefree(conn->allocptr.cookiehost);
+ conn->allocptr.cookiehost = cookiehost;
+ }
+#endif
+
+ conn->allocptr.host = NULL;
+ }
+ else {
+ /* When building Host: headers, we must put the host name within
+ [brackets] if the host name is a plain IPv6-address. RFC2732-style. */
+
+ if(((conn->given->protocol&CURLPROTO_HTTPS) &&
+ (conn->remote_port == PORT_HTTPS)) ||
+ ((conn->given->protocol&CURLPROTO_HTTP) &&
+ (conn->remote_port == PORT_HTTP)) )
+ /* if(HTTPS on port 443) OR (HTTP on port 80) then don't include
+ the port number in the host string */
+ conn->allocptr.host = aprintf("Host: %s%s%s\r\n",
+ conn->bits.ipv6_ip?"[":"",
+ host,
+ conn->bits.ipv6_ip?"]":"");
+ else
+ conn->allocptr.host = aprintf("Host: %s%s%s:%hu\r\n",
+ conn->bits.ipv6_ip?"[":"",
+ host,
+ conn->bits.ipv6_ip?"]":"",
+ conn->remote_port);
+
+ if(!conn->allocptr.host)
+ /* without Host: we can't make a nice request */
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifndef CURL_DISABLE_PROXY
+ if(conn->bits.httpproxy && !conn->bits.tunnel_proxy) {
+ /* Using a proxy but does not tunnel through it */
+
+ /* The path sent to the proxy is in fact the entire URL. But if the remote
+ host is a IDN-name, we must make sure that the request we produce only
+ uses the encoded host name! */
+ if(conn->host.dispname != conn->host.name) {
+ char *url = data->change.url;
+ ptr = strstr(url, conn->host.dispname);
+ if(ptr) {
+ /* This is where the display name starts in the URL, now replace this
+ part with the encoded name. TODO: This method of replacing the host
+ name is rather crude as I believe there's a slight risk that the
+ user has entered a user name or password that contain the host name
+ string. */
+ size_t currlen = strlen(conn->host.dispname);
+ size_t newlen = strlen(conn->host.name);
+ size_t urllen = strlen(url);
+
+ char *newurl;
+
+ newurl = malloc(urllen + newlen - currlen + 1);
+ if(newurl) {
+ /* copy the part before the host name */
+ memcpy(newurl, url, ptr - url);
+ /* append the new host name instead of the old */
+ memcpy(newurl + (ptr - url), conn->host.name, newlen);
+ /* append the piece after the host name */
+ memcpy(newurl + newlen + (ptr - url),
+ ptr + currlen, /* copy the trailing zero byte too */
+ urllen - (ptr-url) - currlen + 1);
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
+ }
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ ppath = data->change.url;
+ if(checkprefix("ftp://", ppath)) {
+ if(data->set.proxy_transfer_mode) {
+ /* when doing ftp, append ;type=<a|i> if not present */
+ char *type = strstr(ppath, ";type=");
+ if(type && type[6] && type[7] == 0) {
+ switch (Curl_raw_toupper(type[6])) {
+ case 'A':
+ case 'D':
+ case 'I':
+ break;
+ default:
+ type = NULL;
+ }
+ }
+ if(!type) {
+ char *p = ftp_typecode;
+ /* avoid sending invalid URLs like ftp://example.com;type=i if the
+ * user specified ftp://example.com without the slash */
+ if(!*data->state.path && ppath[strlen(ppath) - 1] != '/') {
+ *p++ = '/';
+ }
+ snprintf(p, sizeof(ftp_typecode) - 1, ";type=%c",
+ data->set.prefer_ascii ? 'a' : 'i');
+ }
+ }
+ if(conn->bits.user_passwd && !conn->bits.userpwd_in_url)
+ paste_ftp_userpwd = TRUE;
+ }
+ }
+#endif /* CURL_DISABLE_PROXY */
+
+ if(HTTPREQ_POST_FORM == httpreq) {
+ /* we must build the whole post sequence first, so that we have a size of
+ the whole transfer before we start to send it */
+ result = Curl_getformdata(data, &http->sendit, data->set.httppost,
+ Curl_checkheaders(data, "Content-Type:"),
+ &http->postsize);
+ if(result)
+ return result;
+ }
+
+ http->p_accept = Curl_checkheaders(data, "Accept:")?NULL:"Accept: */*\r\n";
+
+ if(( (HTTPREQ_POST == httpreq) ||
+ (HTTPREQ_POST_FORM == httpreq) ||
+ (HTTPREQ_PUT == httpreq) ) &&
+ data->state.resume_from) {
+ /**********************************************************************
+ * Resuming upload in HTTP means that we PUT or POST and that we have
+ * got a resume_from value set. The resume value has already created
+ * a Range: header that will be passed along. We need to "fast forward"
+ * the file the given number of bytes and decrease the assume upload
+ * file size before we continue this venture in the dark lands of HTTP.
+ *********************************************************************/
+
+ if(data->state.resume_from < 0 ) {
+ /*
+ * This is meant to get the size of the present remote-file by itself.
+ * We don't support this now. Bail out!
+ */
+ data->state.resume_from = 0;
+ }
+
+ if(data->state.resume_from && !data->state.this_is_a_follow) {
+ /* do we still game? */
+
+ /* Now, let's read off the proper amount of bytes from the
+ input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_READ_ERROR;
+ }
+ /* when seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ else {
+ curl_off_t passed=0;
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
+ BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ data->set.fread_func(data->state.buffer, 1, readthisamountnow,
+ data->set.in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Could only read %" FORMAT_OFF_T
+ " bytes from the input",
+ passed);
+ return CURLE_READ_ERROR;
+ }
+ } while(passed < data->state.resume_from);
+ }
+ }
+
+ /* now, decrease the size of the read */
+ if(data->set.infilesize>0) {
+ data->set.infilesize -= data->state.resume_from;
+
+ if(data->set.infilesize <= 0) {
+ failf(data, "File already completely uploaded");
+ return CURLE_PARTIAL_FILE;
+ }
+ }
+ /* we've passed, proceed as normal */
+ }
+ }
+ if(data->state.use_range) {
+ /*
+ * A range is selected. We use different headers whether we're downloading
+ * or uploading and we always let customized headers override our internal
+ * ones if any such are specified.
+ */
+ if(((httpreq == HTTPREQ_GET) || (httpreq == HTTPREQ_HEAD)) &&
+ !Curl_checkheaders(data, "Range:")) {
+ /* if a line like this was already allocated, free the previous one */
+ if(conn->allocptr.rangeline)
+ free(conn->allocptr.rangeline);
+ conn->allocptr.rangeline = aprintf("Range: bytes=%s\r\n",
+ data->state.range);
+ }
+ else if((httpreq != HTTPREQ_GET) &&
+ !Curl_checkheaders(data, "Content-Range:")) {
+
+ /* if a line like this was already allocated, free the previous one */
+ if(conn->allocptr.rangeline)
+ free(conn->allocptr.rangeline);
+
+ if(data->set.set_resume_from < 0) {
+ /* Upload resume was asked for, but we don't know the size of the
+ remote part so we tell the server (and act accordingly) that we
+ upload the whole file (again) */
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes 0-%" FORMAT_OFF_T
+ "/%" FORMAT_OFF_T "\r\n",
+ data->set.infilesize - 1, data->set.infilesize);
+
+ }
+ else if(data->state.resume_from) {
+ /* This is because "resume" was selected */
+ curl_off_t total_expected_size=
+ data->state.resume_from + data->set.infilesize;
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s%" FORMAT_OFF_T
+ "/%" FORMAT_OFF_T "\r\n",
+ data->state.range, total_expected_size-1,
+ total_expected_size);
+ }
+ else {
+ /* Range was selected and then we just pass the incoming range and
+ append total size */
+ conn->allocptr.rangeline =
+ aprintf("Content-Range: bytes %s/%" FORMAT_OFF_T "\r\n",
+ data->state.range, data->set.infilesize);
+ }
+ if(!conn->allocptr.rangeline)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Use 1.1 unless the user specifically asked for 1.0 or the server only
+ supports 1.0 */
+ httpstring= use_http_1_1plus(data, conn)?"1.1":"1.0";
+
+ /* initialize a dynamic send-buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* add the main request stuff */
+ /* GET/HEAD/POST/PUT */
+ result = Curl_add_bufferf(req_buffer, "%s ", request);
+ if(result)
+ return result;
+
+ /* url */
+ if(paste_ftp_userpwd)
+ result = Curl_add_bufferf(req_buffer, "ftp://%s:%s@%s",
+ conn->user, conn->passwd,
+ ppath + sizeof("ftp://") - 1);
+ else
+ result = Curl_add_buffer(req_buffer, ppath, strlen(ppath));
+ if(result)
+ return result;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "%s" /* ftp typecode (;type=x) */
+ " HTTP/%s\r\n" /* HTTP version */
+ "%s" /* proxyuserpwd */
+ "%s" /* userpwd */
+ "%s" /* range */
+ "%s" /* user agent */
+ "%s" /* host */
+ "%s" /* accept */
+ "%s" /* TE: */
+ "%s" /* accept-encoding */
+ "%s" /* referer */
+ "%s" /* Proxy-Connection */
+ "%s",/* transfer-encoding */
+
+ ftp_typecode,
+ httpstring,
+ conn->allocptr.proxyuserpwd?
+ conn->allocptr.proxyuserpwd:"",
+ conn->allocptr.userpwd?conn->allocptr.userpwd:"",
+ (data->state.use_range && conn->allocptr.rangeline)?
+ conn->allocptr.rangeline:"",
+ (data->set.str[STRING_USERAGENT] &&
+ *data->set.str[STRING_USERAGENT] &&
+ conn->allocptr.uagent)?
+ conn->allocptr.uagent:"",
+ (conn->allocptr.host?conn->allocptr.host:""),
+ http->p_accept?http->p_accept:"",
+ conn->allocptr.te?conn->allocptr.te:"",
+ (data->set.str[STRING_ENCODING] &&
+ *data->set.str[STRING_ENCODING] &&
+ conn->allocptr.accept_encoding)?
+ conn->allocptr.accept_encoding:"",
+ (data->change.referer && conn->allocptr.ref)?
+ conn->allocptr.ref:"" /* Referer: <data> */,
+ (conn->bits.httpproxy &&
+ !conn->bits.tunnel_proxy &&
+ !Curl_checkheaders(data, "Proxy-Connection:"))?
+ "Proxy-Connection: Keep-Alive\r\n":"",
+ te
+ );
+
+ /*
+ * Free userpwd now --- cannot reuse this for Negotiate and possibly NTLM
+ * with basic and digest, it will be freed anyway by the next request
+ */
+
+ Curl_safefree (conn->allocptr.userpwd);
+ conn->allocptr.userpwd = NULL;
+
+ 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 */
+ int count=0;
+
+ if(data->cookies) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+ co = Curl_cookie_getlist(data->cookies,
+ conn->allocptr.cookiehost?
+ conn->allocptr.cookiehost:host,
+ data->state.path,
+ (conn->handler->protocol&CURLPROTO_HTTPS)?
+ TRUE:FALSE);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+ if(co) {
+ struct Cookie *store=co;
+ /* now loop through all cookies that matched */
+ while(co) {
+ if(co->value) {
+ if(0 == count) {
+ result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ if(result)
+ break;
+ }
+ result = Curl_add_bufferf(req_buffer,
+ "%s%s=%s", count?"; ":"",
+ co->name, co->value);
+ if(result)
+ break;
+ count++;
+ }
+ co = co->next; /* next cookie please */
+ }
+ Curl_cookie_freelist(store, FALSE); /* free the cookie list */
+ }
+ if(addcookies && (CURLE_OK == result)) {
+ if(!count)
+ result = Curl_add_bufferf(req_buffer, "Cookie: ");
+ if(CURLE_OK == result) {
+ result = Curl_add_bufferf(req_buffer, "%s%s",
+ count?"; ":"",
+ addcookies);
+ count++;
+ }
+ }
+ if(count && (CURLE_OK == result))
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+
+ if(result)
+ return result;
+ }
+#endif
+
+ if(data->set.timecondition) {
+ result = Curl_add_timecondition(data, req_buffer);
+ if(result)
+ return result;
+ }
+
+ result = Curl_add_custom_headers(conn, req_buffer);
+ if(result)
+ return result;
+
+ http->postdata = NULL; /* nothing to post at this point */
+ Curl_pgrsSetUploadSize(data, 0); /* upload size is 0 atm */
+
+ /* If 'authdone' is FALSE, we must not set the write socket index to the
+ Curl_transfer() call below, as we're not ready to actually upload any
+ data yet. */
+
+ switch(httpreq) {
+
+ case HTTPREQ_POST_FORM:
+ if(!http->sendit || conn->bits.authneg) {
+ /* nothing to post! */
+ result = Curl_add_bufferf(req_buffer, "Content-Length: 0\r\n\r\n");
+ if(result)
+ return result;
+
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ -1, NULL);
+ break;
+ }
+
+ if(Curl_FormInit(&http->form, http->sendit)) {
+ failf(data, "Internal HTTP POST error!");
+ return CURLE_HTTP_POST_ERROR;
+ }
+
+ /* Get the currently set callback function pointer and store that in the
+ form struct since we might want the actual user-provided callback later
+ on. The conn->fread_func pointer itself will be changed for the
+ multipart case to the function that returns a multipart formatted
+ stream. */
+ http->form.fread_func = conn->fread_func;
+
+ /* Set the read function to read from the generated form data */
+ conn->fread_func = (curl_read_callback)Curl_FormReader;
+ conn->fread_in = &http->form;
+
+ http->sending = HTTPSEND_BODY;
+
+ if(!data->req.upload_chunky &&
+ !Curl_checkheaders(data, "Content-Length:")) {
+ /* only add Content-Length if not uploading chunked */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T "\r\n",
+ http->postsize);
+ if(result)
+ return result;
+ }
+
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+
+ {
+
+ /* Get Content-Type: line from Curl_formpostheader.
+ */
+ char *contentType;
+ size_t linelength=0;
+ contentType = Curl_formpostheader((void *)&http->form,
+ &linelength);
+ if(!contentType) {
+ failf(data, "Could not get Content-Type header line!");
+ return CURLE_HTTP_POST_ERROR;
+ }
+
+ result = Curl_add_buffer(req_buffer, contentType, linelength);
+ if(result)
+ return result;
+ }
+
+ /* make the request end in a true CRLF */
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ /* set upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ /* fire away the whole request to the server */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending POST request");
+ else
+ /* setup variables for the upcoming transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, FIRSTSOCKET,
+ &http->writebytecount);
+
+ if(result) {
+ Curl_formclean(&http->sendit); /* free that whole lot */
+ return result;
+ }
+
+ /* convert the form data */
+ result = Curl_convert_form(data, http->sendit);
+ if(result) {
+ Curl_formclean(&http->sendit); /* free that whole lot */
+ return result;
+ }
+
+ break;
+
+ case HTTPREQ_PUT: /* Let's PUT the data to the server! */
+
+ if(conn->bits.authneg)
+ postsize = 0;
+ else
+ postsize = data->set.infilesize;
+
+ if((postsize != -1) && !data->req.upload_chunky &&
+ !Curl_checkheaders(data, "Content-Length:")) {
+ /* only add Content-Length if not uploading chunked */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T "\r\n",
+ postsize );
+ if(result)
+ return result;
+ }
+
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers */
+ if(result)
+ return result;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, postsize);
+
+ /* this sends the buffer and frees all the buffer resources */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result)
+ failf(data, "Failed sending PUT request");
+ else
+ /* prepare for transfer */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, postsize?FIRSTSOCKET:-1,
+ postsize?&http->writebytecount:NULL);
+ if(result)
+ return result;
+ break;
+
+ case HTTPREQ_POST:
+ /* this is the simple POST, using x-www-form-urlencoded style */
+
+ if(conn->bits.authneg)
+ postsize = 0;
+ else {
+ /* figure out the size of the postfields */
+ postsize = (data->set.postfieldsize != -1)?
+ data->set.postfieldsize:
+ (data->set.postfields? (curl_off_t)strlen(data->set.postfields):-1);
+ }
+ if(!data->req.upload_chunky) {
+ /* We only set Content-Length and allow a custom Content-Length if
+ we don't upload data chunked, as RFC2616 forbids us to set both
+ kinds of headers (Transfer-Encoding: chunked and Content-Length) */
+
+ if(conn->bits.authneg || !Curl_checkheaders(data, "Content-Length:")) {
+ /* we allow replacing this header if not during auth negotiation,
+ although it isn't very wise to actually set your own */
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T"\r\n",
+ postsize);
+ if(result)
+ return result;
+ }
+ }
+
+ if(!Curl_checkheaders(data, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: application/"
+ "x-www-form-urlencoded\r\n");
+ if(result)
+ return result;
+ }
+
+ /* For really small posts we don't use Expect: headers at all, and for
+ the somewhat bigger ones we allow the app to disable it. Just make
+ sure that the expect100header is always set to the preferred value
+ here. */
+ ptr = Curl_checkheaders(data, "Expect:");
+ if(ptr) {
+ data->state.expect100header =
+ Curl_compareheader(ptr, "Expect:", "100-continue");
+ }
+ else if(postsize > TINY_INITIAL_POST_SIZE || postsize < 0) {
+ result = expect100(data, conn, req_buffer);
+ if(result)
+ return result;
+ }
+ else
+ data->state.expect100header = FALSE;
+
+ if(data->set.postfields) {
+
+ if(!data->state.expect100header &&
+ (postsize < MAX_INITIAL_POST_SIZE)) {
+ /* if we don't use expect: 100 AND
+ postsize is less than MAX_INITIAL_POST_SIZE
+
+ then append the post data to the HTTP request header. This limit
+ is no magic limit but only set to prevent really huge POSTs to
+ get the data duplicated with malloc() and family. */
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+
+ if(!data->req.upload_chunky) {
+ /* We're not sending it 'chunked', append it to the request
+ already now to reduce the number if send() calls */
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ included_body = postsize;
+ }
+ else {
+ if(postsize) {
+ /* Append the POST data chunky-style */
+ result = Curl_add_bufferf(req_buffer, "%x\r\n", (int)postsize);
+ if(CURLE_OK == result) {
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(CURLE_OK == result)
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ included_body = postsize + 2;
+ }
+ }
+ if(CURLE_OK == result)
+ result = Curl_add_buffer(req_buffer,
+ "\x30\x0d\x0a\x0d\x0a", 5);
+ /* 0 CR LF CR LF */
+ included_body += 5;
+ }
+ if(result)
+ return result;
+ /* Make sure the progress information is accurate */
+ Curl_pgrsSetUploadSize(data, postsize);
+ }
+ else {
+ /* A huge POST coming up, do data separate from the request */
+ http->postsize = postsize;
+ http->postdata = data->set.postfields;
+
+ http->sending = HTTPSEND_BODY;
+
+ conn->fread_func = (curl_read_callback)readmoredata;
+ conn->fread_in = (void *)conn;
+
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, http->postsize);
+
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+ }
+ }
+ else {
+ result = Curl_add_buffer(req_buffer, "\r\n", 2); /* end of headers! */
+ if(result)
+ return result;
+
+ if(data->req.upload_chunky && conn->bits.authneg) {
+ /* Chunky upload is selected and we're negotiating auth still, send
+ end-of-data only */
+ result = Curl_add_buffer(req_buffer,
+ "\x30\x0d\x0a\x0d\x0a", 5);
+ /* 0 CR LF CR LF */
+ if(result)
+ return result;
+ }
+
+ else if(data->set.postfieldsize) {
+ /* set the upload size to the progress meter */
+ Curl_pgrsSetUploadSize(data, postsize?postsize:-1);
+
+ /* set the pointer to mark that we will send the post body using the
+ read callback, but only if we're not in authenticate
+ negotiation */
+ if(!conn->bits.authneg) {
+ http->postdata = (char *)&http->postdata;
+ http->postsize = postsize;
+ }
+ }
+ }
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn, &data->info.request_size,
+ (size_t)included_body, FIRSTSOCKET);
+
+ if(result)
+ failf(data, "Failed sending HTTP POST request");
+ else
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, http->postdata?FIRSTSOCKET:-1,
+ http->postdata?&http->writebytecount:NULL);
+ break;
+
+ default:
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+
+ if(result)
+ failf(data, "Failed sending HTTP request");
+ else
+ /* HTTP GET/HEAD download: */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ http->postdata?FIRSTSOCKET:-1,
+ http->postdata?&http->writebytecount:NULL);
+ }
+ if(result)
+ return result;
+
+ if(http->writebytecount) {
+ /* if a request-body has been sent off, we make sure this progress is noted
+ properly */
+ Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ if(http->writebytecount >= postsize) {
+ /* already sent the entire request body, mark the "upload" as
+ complete */
+ infof(data, "upload completely sent off: %" FORMAT_OFF_T " out of "
+ "%" FORMAT_OFF_T " bytes\n",
+ http->writebytecount, postsize);
+ data->req.upload_done = TRUE;
+ data->req.keepon &= ~KEEP_SEND; /* we're done writing */
+ data->req.exp100 = EXP100_SEND_DATA; /* already sent */
+ }
+ }
+
+ return result;
+}
+
+/*
+ * checkhttpprefix()
+ *
+ * Returns TRUE if member of the list matches prefix of string
+ */
+static bool
+checkhttpprefix(struct SessionHandle *data,
+ const char *s)
+{
+ struct curl_slist *head = data->set.http200aliases;
+ bool rc = FALSE;
+#ifdef CURL_DOES_CONVERSIONS
+ /* convert from the network encoding using a scratch area */
+ char *scratch = strdup(s);
+ if(NULL == scratch) {
+ failf (data, "Failed to allocate memory for conversion!");
+ return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+ }
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(scratch);
+ return FALSE; /* can't return CURLE_foobar so return FALSE */
+ }
+ s = scratch;
+#endif /* CURL_DOES_CONVERSIONS */
+
+ while(head) {
+ if(checkprefix(head->data, s)) {
+ rc = TRUE;
+ break;
+ }
+ head = head->next;
+ }
+
+ if(!rc && (checkprefix("HTTP/", s)))
+ rc = TRUE;
+
+#ifdef CURL_DOES_CONVERSIONS
+ free(scratch);
+#endif /* CURL_DOES_CONVERSIONS */
+ return rc;
+}
+
+#ifndef CURL_DISABLE_RTSP
+static bool
+checkrtspprefix(struct SessionHandle *data,
+ const char *s)
+{
+
+#ifdef CURL_DOES_CONVERSIONS
+ /* convert from the network encoding using a scratch area */
+ char *scratch = strdup(s);
+ if(NULL == scratch) {
+ failf (data, "Failed to allocate memory for conversion!");
+ return FALSE; /* can't return CURLE_OUT_OF_MEMORY so return FALSE */
+ }
+ if(CURLE_OK != Curl_convert_from_network(data, scratch, strlen(s)+1)) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ free(scratch);
+ return FALSE; /* can't return CURLE_foobar so return FALSE */
+ }
+ s = scratch;
+#else
+ (void)data; /* unused */
+#endif /* CURL_DOES_CONVERSIONS */
+ if(checkprefix("RTSP/", s))
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif /* CURL_DISABLE_RTSP */
+
+static bool
+checkprotoprefix(struct SessionHandle *data, struct connectdata *conn,
+ const char *s)
+{
+#ifndef CURL_DISABLE_RTSP
+ if(conn->handler->protocol & CURLPROTO_RTSP)
+ return checkrtspprefix(data, s);
+#else
+ (void)conn;
+#endif /* CURL_DISABLE_RTSP */
+
+ return checkhttpprefix(data, s);
+}
+
+/*
+ * header_append() copies a chunk of data to the end of the already received
+ * header. We make sure that the full string fit in the allocated header
+ * buffer, or else we enlarge it.
+ */
+static CURLcode header_append(struct SessionHandle *data,
+ struct SingleRequest *k,
+ size_t length)
+{
+ if(k->hbuflen + length >= data->state.headersize) {
+ /* We enlarge the header buffer as it is too small */
+ char *newbuff;
+ size_t hbufp_index;
+ size_t newsize;
+
+ if(k->hbuflen + length > CURL_MAX_HTTP_HEADER) {
+ /* The reason to have a max limit for this is to avoid the risk of a bad
+ server feeding libcurl with a never-ending header that will cause
+ reallocs infinitely */
+ failf (data, "Avoided giant realloc for header (max is %d)!",
+ CURL_MAX_HTTP_HEADER);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ newsize=CURLMAX((k->hbuflen+ length)*3/2, data->state.headersize*2);
+ hbufp_index = k->hbufp - data->state.headerbuff;
+ newbuff = realloc(data->state.headerbuff, newsize);
+ if(!newbuff) {
+ failf (data, "Failed to alloc memory for big header!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->state.headersize=newsize;
+ data->state.headerbuff = newbuff;
+ k->hbufp = data->state.headerbuff + hbufp_index;
+ }
+ memcpy(k->hbufp, k->str_start, length);
+ k->hbufp += length;
+ k->hbuflen += length;
+ *k->hbufp = 0;
+
+ return CURLE_OK;
+}
+
+static void print_http_error(struct SessionHandle *data)
+{
+ struct SingleRequest *k = &data->req;
+ char *beg = k->p;
+
+ /* make sure that data->req.p points to the HTTP status line */
+ if(!strncmp(beg, "HTTP", 4)) {
+
+ /* skip to HTTP status code */
+ beg = strchr(beg, ' ');
+ if(beg && *++beg) {
+
+ /* find trailing CR */
+ char end_char = '\r';
+ char *end = strchr(beg, end_char);
+ if(!end) {
+ /* try to find LF (workaround for non-compliant HTTP servers) */
+ end_char = '\n';
+ end = strchr(beg, end_char);
+ }
+
+ if(end) {
+ /* temporarily replace CR or LF by NUL and print the error message */
+ *end = '\0';
+ failf(data, "The requested URL returned error: %s", beg);
+
+ /* restore the previously replaced CR or LF */
+ *end = end_char;
+ return;
+ }
+ }
+ }
+
+ /* fall-back to printing the HTTP status code only */
+ failf(data, "The requested URL returned error: %d", k->httpcode);
+}
+
+/*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+CURLcode Curl_http_readwrite_headers(struct SessionHandle *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *stop_reading)
+{
+ CURLcode result;
+ struct SingleRequest *k = &data->req;
+
+ /* header line within buffer loop */
+ do {
+ size_t rest_length;
+ size_t full_length;
+ int writetype;
+
+ /* str_start is start of line within buf */
+ k->str_start = k->str;
+
+ /* data is in network encoding so use 0x0a instead of '\n' */
+ k->end_ptr = memchr(k->str_start, 0x0a, *nread);
+
+ if(!k->end_ptr) {
+ /* Not a complete header line within buffer, append the data to
+ the end of the headerbuff. */
+ result = header_append(data, k, *nread);
+ if(result)
+ return result;
+
+ if(!k->headerline && (k->hbuflen>5)) {
+ /* make a first check that this looks like a protocol header */
+ if(!checkprotoprefix(data, conn, data->state.headerbuff)) {
+ /* this is not the beginning of a protocol first header line */
+ k->header = FALSE;
+ k->badheader = HEADER_ALLBAD;
+ break;
+ }
+ }
+
+ break; /* read more and try again */
+ }
+
+ /* decrease the size of the remaining (supposed) header line */
+ rest_length = (k->end_ptr - k->str)+1;
+ *nread -= (ssize_t)rest_length;
+
+ k->str = k->end_ptr + 1; /* move past new line */
+
+ full_length = k->str - k->str_start;
+
+ result = header_append(data, k, full_length);
+ if(result)
+ return result;
+
+ k->end_ptr = k->hbufp;
+ k->p = data->state.headerbuff;
+
+ /****
+ * We now have a FULL header line that p points to
+ *****/
+
+ if(!k->headerline) {
+ /* the first read header */
+ if((k->hbuflen>5) &&
+ !checkprotoprefix(data, conn, data->state.headerbuff)) {
+ /* this is not the beginning of a protocol first header line */
+ k->header = FALSE;
+ if(*nread)
+ /* since there's more, this is a partial bad header */
+ k->badheader = HEADER_PARTHEADER;
+ else {
+ /* this was all we read so it's all a bad header */
+ k->badheader = HEADER_ALLBAD;
+ *nread = (ssize_t)rest_length;
+ }
+ break;
+ }
+ }
+
+ /* headers are in network encoding so
+ use 0x0a and 0x0d instead of '\n' and '\r' */
+ if((0x0a == *k->p) || (0x0d == *k->p)) {
+ size_t headerlen;
+ /* Zero-length header line means end of headers! */
+
+#ifdef CURL_DOES_CONVERSIONS
+ if(0x0d == *k->p) {
+ *k->p = '\r'; /* replace with CR in host encoding */
+ k->p++; /* pass the CR byte */
+ }
+ if(0x0a == *k->p) {
+ *k->p = '\n'; /* replace with LF in host encoding */
+ k->p++; /* pass the LF byte */
+ }
+#else
+ if('\r' == *k->p)
+ k->p++; /* pass the \r byte */
+ if('\n' == *k->p)
+ k->p++; /* pass the \n byte */
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(100 <= k->httpcode && 199 >= k->httpcode) {
+ /*
+ * We have made a HTTP PUT or POST and this is 1.1-lingo
+ * that tells us that the server is OK with this and ready
+ * to receive the data.
+ * However, we'll get more headers now so we must get
+ * back into the header-parsing state!
+ */
+ k->header = TRUE;
+ k->headerline = 0; /* restart the header line counter */
+
+ /* if we did wait for this do enable write now! */
+ if(k->exp100) {
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ }
+ }
+ else {
+ k->header = FALSE; /* no more header to parse! */
+
+ if((k->size == -1) && !k->chunk && !conn->bits.close &&
+ (conn->httpversion >= 11) &&
+ !(conn->handler->protocol & CURLPROTO_RTSP) &&
+ data->set.httpreq != HTTPREQ_HEAD) {
+ /* On HTTP 1.1, when connection is not to get closed, but no
+ Content-Length nor Content-Encoding chunked have been
+ received, according to RFC2616 section 4.4 point 5, we
+ assume that the server will close the connection to
+ signal the end of the document. */
+ infof(data, "no chunk, no close, no size. Assume close to "
+ "signal end\n");
+ conn->bits.close = TRUE;
+ }
+ }
+
+ /*
+ * When all the headers have been parsed, see if we should give
+ * up and return an error.
+ */
+ if(http_should_fail(conn)) {
+ failf (data, "The requested URL returned error: %d",
+ k->httpcode);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+
+ /* now, only output this if the header AND body are requested:
+ */
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ headerlen = k->p - data->state.headerbuff;
+
+ result = Curl_client_write(conn, writetype,
+ data->state.headerbuff,
+ headerlen);
+ if(result)
+ return result;
+
+ data->info.header_size += (long)headerlen;
+ data->req.headerbytecount += (long)headerlen;
+
+ data->req.deductheadercount =
+ (100 <= k->httpcode && 199 >= k->httpcode)?data->req.headerbytecount:0;
+
+ if(!*stop_reading) {
+ /* Curl_http_auth_act() checks what authentication methods
+ * that are available and decides which one (if any) to
+ * use. It will set 'newurl' if an auth method was picked. */
+ result = Curl_http_auth_act(conn);
+
+ if(result)
+ return result;
+
+ if(k->httpcode >= 300) {
+ if((!conn->bits.authneg) && !conn->bits.close &&
+ !conn->bits.rewindaftersend) {
+ /*
+ * General treatment of errors when about to send data. Including :
+ * "417 Expectation Failed", while waiting for 100-continue.
+ *
+ * The check for close above is done simply because of something
+ * else has already deemed the connection to get closed then
+ * something else should've considered the big picture and we
+ * avoid this check.
+ *
+ * rewindaftersend indicates that something has told libcurl to
+ * continue sending even if it gets discarded
+ */
+
+ switch(data->set.httpreq) {
+ case HTTPREQ_PUT:
+ case HTTPREQ_POST:
+ case HTTPREQ_POST_FORM:
+ /* We got an error response. If this happened before the whole
+ * request body has been sent we stop sending and mark the
+ * connection for closure after we've read the entire response.
+ */
+ if(!k->upload_done) {
+ infof(data, "HTTP error before end of send, stop sending\n");
+ conn->bits.close = TRUE; /* close after this */
+ k->upload_done = TRUE;
+ k->keepon &= ~KEEP_SEND; /* don't send */
+ if(data->state.expect100header)
+ k->exp100 = EXP100_FAILED;
+ }
+ break;
+
+ default: /* default label present to avoid compiler warnings */
+ break;
+ }
+ }
+ }
+
+ if(conn->bits.rewindaftersend) {
+ /* We rewind after a complete send, so thus we continue
+ sending now */
+ infof(data, "Keep sending data to get tossed away!\n");
+ k->keepon |= KEEP_SEND;
+ }
+ }
+
+ if(!k->header) {
+ /*
+ * really end-of-headers.
+ *
+ * If we requested a "no body", this is a good time to get
+ * out and return home.
+ */
+ if(data->set.opt_no_body)
+ *stop_reading = TRUE;
+ else {
+ /* If we know the expected size of this document, we set the
+ maximum download size to the size of the expected
+ document or else, we won't know when to stop reading!
+
+ Note that we set the download maximum even if we read a
+ "Connection: close" header, to make sure that
+ "Content-Length: 0" still prevents us from attempting to
+ read the (missing) response-body.
+ */
+ /* According to RFC2616 section 4.4, we MUST ignore
+ Content-Length: headers if we are now receiving data
+ using chunked Transfer-Encoding.
+ */
+ if(k->chunk)
+ k->maxdownload = k->size = -1;
+ }
+ if(-1 != k->size) {
+ /* We do this operation even if no_body is true, since this
+ data might be retrieved later with curl_easy_getinfo()
+ and its CURLINFO_CONTENT_LENGTH_DOWNLOAD option. */
+
+ Curl_pgrsSetDownloadSize(data, k->size);
+ k->maxdownload = k->size;
+ }
+
+ /* If max download size is *zero* (nothing) we already
+ have nothing and can safely return ok now! */
+ if(0 == k->maxdownload)
+ *stop_reading = TRUE;
+
+ if(*stop_reading) {
+ /* we make sure that this socket isn't read more now */
+ k->keepon &= ~KEEP_RECV;
+ }
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ k->str_start, headerlen, conn);
+ break; /* exit header line loop */
+ }
+
+ /* We continue reading headers, so reset the line-based
+ header parsing variables hbufp && hbuflen */
+ k->hbufp = data->state.headerbuff;
+ k->hbuflen = 0;
+ continue;
+ }
+
+ /*
+ * Checks for special headers coming up.
+ */
+
+ if(!k->headerline++) {
+ /* This is the first header, it MUST be the error code line
+ or else we consider this to be the body right away! */
+ int httpversion_major;
+ int rtspversion_major;
+ int nc = 0;
+#ifdef CURL_DOES_CONVERSIONS
+#define HEADER1 scratch
+#define SCRATCHSIZE 21
+ CURLcode res;
+ char scratch[SCRATCHSIZE+1]; /* "HTTP/major.minor 123" */
+ /* We can't really convert this yet because we
+ don't know if it's the 1st header line or the body.
+ So we do a partial conversion into a scratch area,
+ leaving the data at k->p as-is.
+ */
+ strncpy(&scratch[0], k->p, SCRATCHSIZE);
+ scratch[SCRATCHSIZE] = 0; /* null terminate */
+ res = Curl_convert_from_network(data,
+ &scratch[0],
+ SCRATCHSIZE);
+ if(res)
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ return res;
+#else
+#define HEADER1 k->p /* no conversion needed, just use k->p */
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(conn->handler->protocol & CURLPROTO_HTTP) {
+ nc = sscanf(HEADER1,
+ " HTTP/%d.%d %3d",
+ &httpversion_major,
+ &conn->httpversion,
+ &k->httpcode);
+ if(nc==3) {
+ conn->httpversion += 10 * httpversion_major;
+ }
+ else {
+ /* this is the real world, not a Nirvana
+ NCSA 1.5.x returns this crap when asked for HTTP/1.1
+ */
+ nc=sscanf(HEADER1, " HTTP %3d", &k->httpcode);
+ conn->httpversion = 10;
+
+ /* If user has set option HTTP200ALIASES,
+ compare header line against list of aliases
+ */
+ if(!nc) {
+ if(checkhttpprefix(data, k->p)) {
+ nc = 1;
+ k->httpcode = 200;
+ conn->httpversion = 10;
+ }
+ }
+ }
+ }
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ nc = sscanf(HEADER1,
+ " RTSP/%d.%d %3d",
+ &rtspversion_major,
+ &conn->rtspversion,
+ &k->httpcode);
+ if(nc==3) {
+ conn->rtspversion += 10 * rtspversion_major;
+ conn->httpversion = 11; /* For us, RTSP acts like HTTP 1.1 */
+ }
+ else {
+ /* TODO: do we care about the other cases here? */
+ nc = 0;
+ }
+ }
+
+ if(nc) {
+ data->info.httpcode = k->httpcode;
+
+ data->info.httpversion = conn->httpversion;
+ if(!data->state.httpversion ||
+ data->state.httpversion > conn->httpversion)
+ /* store the lowest server version we encounter */
+ data->state.httpversion = conn->httpversion;
+
+ /*
+ * This code executes as part of processing the header. As a
+ * result, it's not totally clear how to interpret the
+ * response code yet as that depends on what other headers may
+ * be present. 401 and 407 may be errors, but may be OK
+ * depending on how authentication is working. Other codes
+ * are definitely errors, so give up here.
+ */
+ if(data->set.http_fail_on_error && (k->httpcode >= 400) &&
+ ((k->httpcode != 401) || !conn->bits.user_passwd) &&
+ ((k->httpcode != 407) || !conn->bits.proxy_user_passwd) ) {
+
+ if(data->state.resume_from &&
+ (data->set.httpreq==HTTPREQ_GET) &&
+ (k->httpcode == 416)) {
+ /* "Requested Range Not Satisfiable", just proceed and
+ pretend this is no error */
+ }
+ else {
+ /* serious error, go home! */
+ print_http_error(data);
+ return CURLE_HTTP_RETURNED_ERROR;
+ }
+ }
+
+ if(conn->httpversion == 10) {
+ /* Default action for HTTP/1.0 must be to close, unless
+ we get one of those fancy headers that tell us the
+ server keeps it open for us! */
+ infof(data, "HTTP 1.0, assume close after body\n");
+ conn->bits.close = TRUE;
+ }
+ else if(conn->httpversion >= 11 &&
+ !conn->bits.close) {
+ struct connectbundle *cb_ptr;
+
+ /* If HTTP version is >= 1.1 and connection is persistent
+ server supports pipelining. */
+ DEBUGF(infof(data,
+ "HTTP 1.1 or later with persistent connection, "
+ "pipelining supported\n"));
+ /* Activate pipelining if needed */
+ cb_ptr = conn->bundle;
+ if(cb_ptr) {
+ if(!Curl_pipeline_site_blacklisted(data, conn))
+ cb_ptr->server_supports_pipelining = TRUE;
+ }
+ }
+
+ switch(k->httpcode) {
+ case 204:
+ /* (quote from RFC2616, section 10.2.5): The server has
+ * fulfilled the request but does not need to return an
+ * entity-body ... The 204 response MUST NOT include a
+ * message-body, and thus is always terminated by the first
+ * empty line after the header fields. */
+ /* FALLTHROUGH */
+ case 304:
+ /* (quote from RFC2616, section 10.3.5): The 304 response
+ * MUST NOT contain a message-body, and thus is always
+ * terminated by the first empty line after the header
+ * fields. */
+ if(data->set.timecondition)
+ data->info.timecond = TRUE;
+ k->size=0;
+ k->maxdownload=0;
+ k->ignorecl = TRUE; /* ignore Content-Length headers */
+ break;
+ default:
+ /* nothing */
+ break;
+ }
+ }
+ else {
+ k->header = FALSE; /* this is not a header line */
+ break;
+ }
+ }
+
+ result = Curl_convert_from_network(data, k->p, strlen(k->p));
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+ /* Check for Content-Length: header lines to get size */
+ if(!k->ignorecl && !data->set.ignorecl &&
+ checkprefix("Content-Length:", k->p)) {
+ curl_off_t contentlength = curlx_strtoofft(k->p+15, NULL, 10);
+ if(data->set.max_filesize &&
+ contentlength > data->set.max_filesize) {
+ failf(data, "Maximum file size exceeded");
+ return CURLE_FILESIZE_EXCEEDED;
+ }
+ if(contentlength >= 0) {
+ k->size = contentlength;
+ k->maxdownload = k->size;
+ /* we set the progress download size already at this point
+ just to make it easier for apps/callbacks to extract this
+ info as soon as possible */
+ Curl_pgrsSetDownloadSize(data, k->size);
+ }
+ else {
+ /* Negative Content-Length is really odd, and we know it
+ happens for example when older Apache servers send large
+ files */
+ conn->bits.close = TRUE;
+ infof(data, "Negative content-length: %" FORMAT_OFF_T
+ ", closing after transfer\n", contentlength);
+ }
+ }
+ /* check for Content-Type: header lines to get the MIME-type */
+ else if(checkprefix("Content-Type:", k->p)) {
+ char *contenttype = copy_header_value(k->p);
+ if(!contenttype)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*contenttype)
+ /* ignore empty data */
+ free(contenttype);
+ else {
+ Curl_safefree(data->info.contenttype);
+ data->info.contenttype = contenttype;
+ }
+ }
+ else if(checkprefix("Server:", k->p)) {
+ char *server_name = copy_header_value(k->p);
+
+ /* Turn off pipelining if the server version is blacklisted */
+ if(conn->bundle && conn->bundle->server_supports_pipelining) {
+ if(Curl_pipeline_server_blacklisted(data, server_name))
+ conn->bundle->server_supports_pipelining = FALSE;
+ }
+ Curl_safefree(server_name);
+ }
+ else if((conn->httpversion == 10) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(k->p,
+ "Proxy-Connection:", "keep-alive")) {
+ /*
+ * When a HTTP/1.0 reply comes when using a proxy, the
+ * 'Proxy-Connection: keep-alive' line tells us the
+ * connection will be kept alive for our pleasure.
+ * Default action for 1.0 is to close.
+ */
+ conn->bits.close = FALSE; /* don't close when done */
+ infof(data, "HTTP/1.0 proxy connection set to keep alive!\n");
+ }
+ else if((conn->httpversion == 11) &&
+ conn->bits.httpproxy &&
+ Curl_compareheader(k->p,
+ "Proxy-Connection:", "close")) {
+ /*
+ * We get a HTTP/1.1 response from a proxy and it says it'll
+ * close down after this transfer.
+ */
+ conn->bits.close = TRUE; /* close when done */
+ infof(data, "HTTP/1.1 proxy connection set close!\n");
+ }
+ else if((conn->httpversion == 10) &&
+ Curl_compareheader(k->p, "Connection:", "keep-alive")) {
+ /*
+ * A HTTP/1.0 reply with the 'Connection: keep-alive' line
+ * tells us the connection will be kept alive for our
+ * pleasure. Default action for 1.0 is to close.
+ *
+ * [RFC2068, section 19.7.1] */
+ conn->bits.close = FALSE; /* don't close when done */
+ infof(data, "HTTP/1.0 connection set to keep alive!\n");
+ }
+ else if(Curl_compareheader(k->p, "Connection:", "close")) {
+ /*
+ * [RFC 2616, section 8.1.2.1]
+ * "Connection: close" is HTTP/1.1 language and means that
+ * the connection will close when this request has been
+ * served.
+ */
+ conn->bits.close = TRUE; /* close when done */
+ }
+ else if(checkprefix("Transfer-Encoding:", k->p)) {
+ /* One or more encodings. We check for chunked and/or a compression
+ algorithm. */
+ /*
+ * [RFC 2616, section 3.6.1] A 'chunked' transfer encoding
+ * means that the server will send a series of "chunks". Each
+ * chunk starts with line with info (including size of the
+ * coming block) (terminated with CRLF), then a block of data
+ * with the previously mentioned size. There can be any amount
+ * of chunks, and a chunk-data set to zero signals the
+ * end-of-chunks. */
+
+ char *start;
+
+ /* Find the first non-space letter */
+ start = k->p + 18;
+
+ for(;;) {
+ /* skip whitespaces and commas */
+ while(*start && (ISSPACE(*start) || (*start == ',')))
+ start++;
+
+ if(checkprefix("chunked", start)) {
+ k->chunk = TRUE; /* chunks coming our way */
+
+ /* init our chunky engine */
+ Curl_httpchunk_init(conn);
+
+ start += 7;
+ }
+
+ if(k->auto_decoding)
+ /* TODO: we only support the first mentioned compression for now */
+ break;
+
+ if(checkprefix("identity", start)) {
+ k->auto_decoding = IDENTITY;
+ start += 8;
+ }
+ else if(checkprefix("deflate", start)) {
+ k->auto_decoding = DEFLATE;
+ start += 7;
+ }
+ else if(checkprefix("gzip", start)) {
+ k->auto_decoding = GZIP;
+ start += 4;
+ }
+ else if(checkprefix("x-gzip", start)) {
+ k->auto_decoding = GZIP;
+ start += 6;
+ }
+ else if(checkprefix("compress", start)) {
+ k->auto_decoding = COMPRESS;
+ start += 8;
+ }
+ else if(checkprefix("x-compress", start)) {
+ k->auto_decoding = COMPRESS;
+ start += 10;
+ }
+ else
+ /* unknown! */
+ break;
+
+ }
+
+ }
+ else if(checkprefix("Content-Encoding:", k->p) &&
+ data->set.str[STRING_ENCODING]) {
+ /*
+ * Process Content-Encoding. Look for the values: identity,
+ * gzip, deflate, compress, x-gzip and x-compress. x-gzip and
+ * x-compress are the same as gzip and compress. (Sec 3.5 RFC
+ * 2616). zlib cannot handle compress. However, errors are
+ * handled further down when the response body is processed
+ */
+ char *start;
+
+ /* Find the first non-space letter */
+ start = k->p + 17;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ /* Record the content-encoding for later use */
+ if(checkprefix("identity", start))
+ k->auto_decoding = IDENTITY;
+ else if(checkprefix("deflate", start))
+ k->auto_decoding = DEFLATE;
+ else if(checkprefix("gzip", start)
+ || checkprefix("x-gzip", start))
+ k->auto_decoding = GZIP;
+ else if(checkprefix("compress", start)
+ || checkprefix("x-compress", start))
+ k->auto_decoding = COMPRESS;
+ }
+ else if(checkprefix("Content-Range:", k->p)) {
+ /* Content-Range: bytes [num]-
+ Content-Range: bytes: [num]-
+ Content-Range: [num]-
+
+ The second format was added since Sun's webserver
+ JavaWebServer/1.1.1 obviously sends the header this way!
+ The third added since some servers use that!
+ */
+
+ char *ptr = k->p + 14;
+
+ /* Move forward until first digit */
+ while(*ptr && !ISDIGIT(*ptr))
+ ptr++;
+
+ k->offset = curlx_strtoofft(ptr, NULL, 10);
+
+ if(data->state.resume_from == k->offset)
+ /* we asked for a resume and we got it */
+ k->content_range = TRUE;
+ }
+#if !defined(CURL_DISABLE_COOKIES)
+ else if(data->cookies &&
+ checkprefix("Set-Cookie:", k->p)) {
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE,
+ CURL_LOCK_ACCESS_SINGLE);
+ Curl_cookie_add(data,
+ data->cookies, TRUE, k->p+11,
+ /* If there is a custom-set Host: name, use it
+ here, or else use real peer host name. */
+ conn->allocptr.cookiehost?
+ conn->allocptr.cookiehost:conn->host.name,
+ data->state.path);
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+ }
+#endif
+ else if(checkprefix("Last-Modified:", k->p) &&
+ (data->set.timecondition || data->set.get_filetime) ) {
+ time_t secs=time(NULL);
+ k->timeofdoc = curl_getdate(k->p+strlen("Last-Modified:"),
+ &secs);
+ if(data->set.get_filetime)
+ data->info.filetime = (long)k->timeofdoc;
+ }
+ else if((checkprefix("WWW-Authenticate:", k->p) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", k->p) &&
+ (407 == k->httpcode))) {
+ result = Curl_http_input_auth(conn, k->httpcode, k->p);
+ if(result)
+ return result;
+ }
+ else if((k->httpcode >= 300 && k->httpcode < 400) &&
+ checkprefix("Location:", k->p) &&
+ !data->req.location) {
+ /* this is the URL that the server advises us to use instead */
+ char *location = copy_header_value(k->p);
+ if(!location)
+ return CURLE_OUT_OF_MEMORY;
+ if(!*location)
+ /* ignore empty data */
+ free(location);
+ else {
+ data->req.location = location;
+
+ if(data->set.http_follow_location) {
+ DEBUGASSERT(!data->req.newurl);
+ data->req.newurl = strdup(data->req.location); /* clone */
+ if(!data->req.newurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* some cases of POST and PUT etc needs to rewind the data
+ stream at this point */
+ result = http_perhapsrewind(conn);
+ if(result)
+ return result;
+ }
+ }
+ }
+ else if(conn->handler->protocol & CURLPROTO_RTSP) {
+ result = Curl_rtsp_parseheader(conn, k->p);
+ if(result)
+ return result;
+ }
+
+ /*
+ * End of header-checks. Write them to the client.
+ */
+
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ k->p, (size_t)k->hbuflen, conn);
+
+ result = Curl_client_write(conn, writetype, k->p, k->hbuflen);
+ if(result)
+ return result;
+
+ data->info.header_size += (long)k->hbuflen;
+ data->req.headerbytecount += (long)k->hbuflen;
+
+ /* reset hbufp pointer && hbuflen */
+ k->hbufp = data->state.headerbuff;
+ k->hbuflen = 0;
+ }
+ while(!*stop_reading && *k->str); /* header line within buffer */
+
+ /* We might have reached the end of the header part here, but
+ there might be a non-header part left in the end of the read
+ buffer. */
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_HTTP */
diff --git a/libs/libcurl/src/http.h b/libs/libcurl/src/http.h
new file mode 100644
index 0000000000..a506238a66
--- /dev/null
+++ b/libs/libcurl/src/http.h
@@ -0,0 +1,186 @@
+#ifndef HEADER_CURL_HTTP_H
+#define HEADER_CURL_HTTP_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"
+
+#ifndef CURL_DISABLE_HTTP
+
+#ifdef USE_NGHTTP2
+#include <nghttp2/nghttp2.h>
+#endif
+
+extern const struct Curl_handler Curl_handler_http;
+
+#ifdef USE_SSL
+extern const struct Curl_handler Curl_handler_https;
+#endif
+
+bool Curl_compareheader(const char *headerline, /* line to check */
+ const char *header, /* header keyword _with_ colon */
+ const char *content); /* content string to find */
+
+char *Curl_checkheaders(struct SessionHandle *data, const char *thisheader);
+
+/* ------------------------------------------------------------------------- */
+/*
+ * The add_buffer series of functions are used to build one large memory chunk
+ * from repeated function invokes. Used so that the entire HTTP request can
+ * be sent in one go.
+ */
+struct Curl_send_buffer {
+ char *buffer;
+ size_t size_max;
+ size_t size_used;
+};
+typedef struct Curl_send_buffer Curl_send_buffer;
+
+Curl_send_buffer *Curl_add_buffer_init(void);
+CURLcode Curl_add_bufferf(Curl_send_buffer *in, const char *fmt, ...);
+CURLcode Curl_add_buffer(Curl_send_buffer *in, const void *inptr, size_t size);
+CURLcode Curl_add_buffer_send(Curl_send_buffer *in,
+ struct connectdata *conn,
+ long *bytes_written,
+ size_t included_body_bytes,
+ int socketindex);
+
+CURLcode Curl_add_timecondition(struct SessionHandle *data,
+ Curl_send_buffer *buf);
+CURLcode Curl_add_custom_headers(struct connectdata *conn,
+ Curl_send_buffer *req_buffer);
+
+/* protocol-specific functions set up to be called by the main engine */
+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);
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn, char *datap,
+ ssize_t length, ssize_t *wrote);
+
+/* These functions are in http.c */
+void Curl_http_auth_stage(struct SessionHandle *data, int stage);
+CURLcode Curl_http_input_auth(struct connectdata *conn,
+ int httpcode, const char *header);
+CURLcode Curl_http_auth_act(struct connectdata *conn);
+CURLcode Curl_http_perhapsrewind(struct connectdata *conn);
+
+/* If only the PICKNONE bit is set, there has been a round-trip and we
+ selected to use no auth at all. Ie, we actively select no auth, as opposed
+ to not having one selected. The other CURLAUTH_* defines are present in the
+ public curl/curl.h header. */
+#define CURLAUTH_PICKNONE (1<<30) /* don't use auth */
+
+/* MAX_INITIAL_POST_SIZE indicates the number of bytes that will make the POST
+ data get included in the initial data chunk sent to the server. If the
+ data is larger than this, it will automatically get split up in multiple
+ system calls.
+
+ This value used to be fairly big (100K), but we must take into account that
+ if the server rejects the POST due for authentication reasons, this data
+ will always be uncondtionally sent and thus it may not be larger than can
+ always be afforded to send twice.
+
+ It must not be greater than 64K to work on VMS.
+*/
+#ifndef MAX_INITIAL_POST_SIZE
+#define MAX_INITIAL_POST_SIZE (64*1024)
+#endif
+
+#ifndef TINY_INITIAL_POST_SIZE
+#define TINY_INITIAL_POST_SIZE 1024
+#endif
+
+#endif /* CURL_DISABLE_HTTP */
+
+/****************************************************************************
+ * HTTP unique setup
+ ***************************************************************************/
+struct HTTP {
+ struct FormData *sendit;
+ curl_off_t postsize; /* off_t to handle large file sizes */
+ const char *postdata;
+
+ const char *p_pragma; /* Pragma: string */
+ const char *p_accept; /* Accept: string */
+ curl_off_t readbytecount;
+ curl_off_t writebytecount;
+
+ /* For FORM posting */
+ struct Form form;
+
+ struct back {
+ curl_read_callback fread_func; /* backup storage for fread pointer */
+ void *fread_in; /* backup storage for fread_in pointer */
+ const char *postdata;
+ curl_off_t postsize;
+ } backup;
+
+ enum {
+ HTTPSEND_NADA, /* init */
+ HTTPSEND_REQUEST, /* sending a request */
+ HTTPSEND_BODY, /* sending body */
+ HTTPSEND_LAST /* never use this */
+ } sending;
+
+ void *send_buffer; /* used if the request couldn't be sent in one chunk,
+ 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,
+ bool *stop_reading);
+
+/**
+ * Curl_http_output_auth() setups the authentication headers for the
+ * host/proxy and the correct authentication
+ * method. conn->data->state.authdone is set to TRUE when authentication is
+ * done.
+ *
+ * @param conn all information about the current connection
+ * @param request pointer to the request keyword
+ * @param path pointer to the requested path
+ * @param proxytunnel boolean if this is the request setting up a "proxy
+ * tunnel"
+ *
+ * @returns CURLcode
+ */
+CURLcode
+Curl_http_output_auth(struct connectdata *conn,
+ const char *request,
+ const char *path,
+ bool proxytunnel); /* TRUE if this is the request setting
+ up the proxy tunnel */
+
+#endif /* HEADER_CURL_HTTP_H */
+
diff --git a/libs/libcurl/src/http2.c b/libs/libcurl/src/http2.c
new file mode 100644
index 0000000000..b876436e1a
--- /dev/null
+++ b/libs/libcurl/src/http2.c
@@ -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
diff --git a/libs/libcurl/src/http2.h b/libs/libcurl/src/http2.h
new file mode 100644
index 0000000000..09b91d1122
--- /dev/null
+++ b/libs/libcurl/src/http2.h
@@ -0,0 +1,42 @@
+#ifndef HEADER_CURL_HTTP2_H
+#define HEADER_CURL_HTTP2_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"
+
+#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);
+
+CURLcode Curl_http2_request(Curl_send_buffer *req,
+ struct connectdata *conn);
+#else /* USE_NGHTTP2 */
+#define Curl_http2_request(x,y) CURLE_OK
+#endif
+
+#endif /* HEADER_CURL_HTTP2_H */
+
diff --git a/libs/libcurl/src/http_chunks.c b/libs/libcurl/src/http_chunks.c
new file mode 100644
index 0000000000..e9fddf5889
--- /dev/null
+++ b/libs/libcurl/src/http_chunks.c
@@ -0,0 +1,397 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h" /* it includes http_chunks.h */
+#include "sendf.h" /* for the client write stuff */
+
+#include "content_encoding.h"
+#include "http.h"
+#include "curl_memory.h"
+#include "non-ascii.h" /* for Curl_convert_to_network prototype */
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Chunk format (simplified):
+ *
+ * <HEX SIZE>[ chunk extension ] CRLF
+ * <DATA> CRLF
+ *
+ * Highlights from RFC2616 section 3.6 say:
+
+ The chunked encoding modifies the body of a message in order to
+ transfer it as a series of chunks, each with its own size indicator,
+ followed by an OPTIONAL trailer containing entity-header fields. This
+ allows dynamically produced content to be transferred along with the
+ information necessary for the recipient to verify that it has
+ received the full message.
+
+ Chunked-Body = *chunk
+ last-chunk
+ trailer
+ CRLF
+
+ chunk = chunk-size [ chunk-extension ] CRLF
+ chunk-data CRLF
+ chunk-size = 1*HEX
+ last-chunk = 1*("0") [ chunk-extension ] CRLF
+
+ chunk-extension= *( ";" chunk-ext-name [ "=" chunk-ext-val ] )
+ chunk-ext-name = token
+ chunk-ext-val = token | quoted-string
+ chunk-data = chunk-size(OCTET)
+ trailer = *(entity-header CRLF)
+
+ The chunk-size field is a string of hex digits indicating the size of
+ the chunk. The chunked encoding is ended by any chunk whose size is
+ zero, followed by the trailer, which is terminated by an empty line.
+
+ */
+
+/* Check for an ASCII hex digit.
+ We avoid the use of isxdigit to accommodate non-ASCII hosts. */
+static bool Curl_isxdigit(char digit)
+{
+ return ( (digit >= 0x30 && digit <= 0x39) /* 0-9 */
+ || (digit >= 0x41 && digit <= 0x46) /* A-F */
+ || (digit >= 0x61 && digit <= 0x66) /* a-f */ ) ? TRUE : FALSE;
+}
+
+void Curl_httpchunk_init(struct connectdata *conn)
+{
+ struct Curl_chunker *chunk = &conn->chunk;
+ chunk->hexindex=0; /* start at 0 */
+ chunk->dataleft=0; /* no data left yet! */
+ chunk->state = CHUNK_HEX; /* we get hex first! */
+}
+
+/*
+ * chunk_read() returns a OK for normal operations, or a positive return code
+ * for errors. STOP means this sequence of chunks is complete. The 'wrote'
+ * argument is set to tell the caller how many bytes we actually passed to the
+ * client (for byte-counting and whatever).
+ *
+ * The states and the state-machine is further explained in the header file.
+ *
+ * This function always uses ASCII hex values to accommodate non-ASCII hosts.
+ * For example, 0x0d and 0x0a are used instead of '\r' and '\n'.
+ */
+CHUNKcode Curl_httpchunk_read(struct connectdata *conn,
+ char *datap,
+ ssize_t datalen,
+ ssize_t *wrotep)
+{
+ CURLcode result=CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct Curl_chunker *ch = &conn->chunk;
+ struct SingleRequest *k = &data->req;
+ size_t piece;
+ size_t length = (size_t)datalen;
+ size_t *wrote = (size_t *)wrotep;
+
+ *wrote = 0; /* nothing's written yet */
+
+ /* the original data is written to the client, but we go on with the
+ chunk read process, to properly calculate the content length*/
+ if(data->set.http_te_skip && !k->ignorebody) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap, datalen);
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+ }
+
+ while(length) {
+ switch(ch->state) {
+ case CHUNK_HEX:
+ if(Curl_isxdigit(*datap)) {
+ if(ch->hexindex < MAXNUM_SIZE) {
+ ch->hexbuffer[ch->hexindex] = *datap;
+ datap++;
+ length--;
+ ch->hexindex++;
+ }
+ else {
+ return CHUNKE_TOO_LONG_HEX; /* longer hex than we support */
+ }
+ }
+ else {
+ if(0 == ch->hexindex) {
+ /* This is illegal data, we received junk where we expected
+ a hexadecimal digit. */
+ return CHUNKE_ILLEGAL_HEX;
+ }
+ /* length and datap are unmodified */
+ ch->hexbuffer[ch->hexindex]=0;
+
+ /* convert to host encoding before calling strtoul */
+ result = Curl_convert_from_network(conn->data, ch->hexbuffer,
+ ch->hexindex);
+ if(result) {
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad hex character */
+ return(CHUNKE_ILLEGAL_HEX);
+ }
+
+ ch->datasize=strtoul(ch->hexbuffer, NULL, 16);
+ ch->state = CHUNK_POSTHEX;
+ }
+ break;
+
+ case CHUNK_POSTHEX:
+ /* In this state, we're waiting for CRLF to arrive. We support
+ this to allow so called chunk-extensions to show up here
+ before the CRLF comes. */
+ if(*datap == 0x0d)
+ ch->state = CHUNK_CR;
+ length--;
+ datap++;
+ break;
+
+ case CHUNK_CR:
+ /* waiting for the LF */
+ if(*datap == 0x0a) {
+ /* we're now expecting data to come, unless size was zero! */
+ if(0 == ch->datasize) {
+ ch->state = CHUNK_TRAILER; /* now check for trailers */
+ conn->trlPos=0;
+ }
+ else {
+ ch->state = CHUNK_DATA;
+ }
+ }
+ else
+ /* previously we got a fake CR, go back to CR waiting! */
+ ch->state = CHUNK_CR;
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_DATA:
+ /* we get pure and fine data
+
+ We expect another 'datasize' of data. We have 'length' right now,
+ it can be more or less than 'datasize'. Get the smallest piece.
+ */
+ piece = (ch->datasize >= length)?length:ch->datasize;
+
+ /* Write the data portion available */
+#ifdef HAVE_LIBZ
+ switch (conn->data->set.http_ce_skip?
+ IDENTITY : data->req.auto_decoding) {
+ case IDENTITY:
+#endif
+ if(!k->ignorebody) {
+ if(!data->set.http_te_skip)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, datap,
+ piece);
+ else
+ result = CURLE_OK;
+ }
+#ifdef HAVE_LIBZ
+ break;
+
+ case DEFLATE:
+ /* update data->req.keep.str to point to the chunk data. */
+ data->req.str = datap;
+ result = Curl_unencode_deflate_write(conn, &data->req,
+ (ssize_t)piece);
+ break;
+
+ case GZIP:
+ /* update data->req.keep.str to point to the chunk data. */
+ data->req.str = datap;
+ result = Curl_unencode_gzip_write(conn, &data->req,
+ (ssize_t)piece);
+ break;
+
+ case COMPRESS:
+ default:
+ failf (conn->data,
+ "Unrecognized content encoding type. "
+ "libcurl understands `identity', `deflate' and `gzip' "
+ "content encodings.");
+ return CHUNKE_BAD_ENCODING;
+ }
+#endif
+
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+
+ *wrote += piece;
+
+ ch->datasize -= piece; /* decrease amount left to expect */
+ datap += piece; /* move read pointer forward */
+ length -= piece; /* decrease space left in this round */
+
+ if(0 == ch->datasize)
+ /* end of data this round, we now expect a trailing CRLF */
+ ch->state = CHUNK_POSTCR;
+ break;
+
+ case CHUNK_POSTCR:
+ if(*datap == 0x0d) {
+ ch->state = CHUNK_POSTLF;
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+
+ break;
+
+ case CHUNK_POSTLF:
+ if(*datap == 0x0a) {
+ /*
+ * The last one before we go back to hex state and start all
+ * over.
+ */
+ Curl_httpchunk_init(conn);
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+
+ break;
+
+ case CHUNK_TRAILER:
+ if(*datap == 0x0d) {
+ /* this is the end of a trailer, but if the trailer was zero bytes
+ there was no trailer and we move on */
+
+ if(conn->trlPos) {
+ /* we allocate trailer with 3 bytes extra room to fit this */
+ conn->trailer[conn->trlPos++]=0x0d;
+ conn->trailer[conn->trlPos++]=0x0a;
+ conn->trailer[conn->trlPos]=0;
+
+ /* Convert to host encoding before calling Curl_client_write */
+ result = Curl_convert_from_network(conn->data, conn->trailer,
+ conn->trlPos);
+ if(result)
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* Treat it as a bad chunk */
+ return CHUNKE_BAD_CHUNK;
+
+ if(!data->set.http_te_skip) {
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ conn->trailer, conn->trlPos);
+ if(result)
+ return CHUNKE_WRITE_ERROR;
+ }
+ conn->trlPos=0;
+ ch->state = CHUNK_TRAILER_CR;
+ }
+ else {
+ /* no trailer, we're on the final CRLF pair */
+ ch->state = CHUNK_TRAILER_POSTCR;
+ break; /* don't advance the pointer */
+ }
+ }
+ else {
+ /* conn->trailer is assumed to be freed in url.c on a
+ connection basis */
+ if(conn->trlPos >= conn->trlMax) {
+ /* we always allocate three extra bytes, just because when the full
+ header has been received we append CRLF\0 */
+ char *ptr;
+ if(conn->trlMax) {
+ conn->trlMax *= 2;
+ ptr = realloc(conn->trailer, conn->trlMax + 3);
+ }
+ else {
+ conn->trlMax=128;
+ ptr = malloc(conn->trlMax + 3);
+ }
+ if(!ptr)
+ return CHUNKE_OUT_OF_MEMORY;
+ conn->trailer = ptr;
+ }
+ conn->trailer[conn->trlPos++]=*datap;
+ }
+ datap++;
+ length--;
+ break;
+
+ case CHUNK_TRAILER_CR:
+ if(*datap == 0x0a) {
+ ch->state = CHUNK_TRAILER_POSTCR;
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ break;
+
+ case CHUNK_TRAILER_POSTCR:
+ /* We enter this state when a CR should arrive so we expect to
+ have to first pass a CR before we wait for LF */
+ if(*datap != 0x0d) {
+ /* not a CR then it must be another header in the trailer */
+ ch->state = CHUNK_TRAILER;
+ break;
+ }
+ datap++;
+ length--;
+ /* now wait for the final LF */
+ ch->state = CHUNK_STOP;
+ break;
+
+ case CHUNK_STOPCR:
+ /* Read the final CRLF that ends all chunk bodies */
+
+ if(*datap == 0x0d) {
+ ch->state = CHUNK_STOP;
+ datap++;
+ length--;
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+ break;
+
+ case CHUNK_STOP:
+ if(*datap == 0x0a) {
+ length--;
+
+ /* Record the length of any data left in the end of the buffer
+ even if there's no more chunks to read */
+
+ ch->dataleft = length;
+ return CHUNKE_STOP; /* return stop */
+ }
+ else
+ return CHUNKE_BAD_CHUNK;
+
+ default:
+ return CHUNKE_STATE_ERROR;
+ }
+ }
+ return CHUNKE_OK;
+}
+#endif /* CURL_DISABLE_HTTP */
diff --git a/libs/libcurl/src/http_chunks.h b/libs/libcurl/src/http_chunks.h
new file mode 100644
index 0000000000..b999ab53b8
--- /dev/null
+++ b/libs/libcurl/src/http_chunks.h
@@ -0,0 +1,108 @@
+#ifndef HEADER_CURL_HTTP_CHUNKS_H
+#define HEADER_CURL_HTTP_CHUNKS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+/*
+ * The longest possible hexadecimal number we support in a chunked transfer.
+ * Weird enough, RFC2616 doesn't set a maximum size! Since we use strtoul()
+ * to convert it, we "only" support 2^32 bytes chunk data.
+ */
+#define MAXNUM_SIZE 16
+
+typedef enum {
+ CHUNK_FIRST, /* never use */
+
+ /* In this we await and buffer all hexadecimal digits until we get one
+ that isn't a hexadecimal digit. When done, we go POSTHEX */
+ CHUNK_HEX,
+
+ /* We have received the hexadecimal digit and we eat all characters until
+ we get a CRLF pair. When we see a CR we go to the CR state. */
+ CHUNK_POSTHEX,
+
+ /* A single CR has been found and we should get a LF right away in this
+ state or we go back to POSTHEX. When LF is received, we go to DATA.
+ If the size given was zero, we set state to STOP and return. */
+ CHUNK_CR,
+
+ /* We eat the amount of data specified. When done, we move on to the
+ POST_CR state. */
+ CHUNK_DATA,
+
+ /* POSTCR should get a CR and nothing else, then move to POSTLF */
+ CHUNK_POSTCR,
+
+ /* POSTLF should get a LF and nothing else, then move back to HEX as the
+ CRLF combination marks the end of a chunk */
+ CHUNK_POSTLF,
+
+ /* Each Chunk body should end with a CRLF. Read a CR and nothing else,
+ then move to CHUNK_STOP */
+ CHUNK_STOPCR,
+
+ /* This is mainly used to really mark that we're out of the game.
+ NOTE: that there's a 'dataleft' field in the struct that will tell how
+ many bytes that were not passed to the client in the end of the last
+ buffer! */
+ CHUNK_STOP,
+
+ /* At this point optional trailer headers can be found, unless the next line
+ is CRLF */
+ CHUNK_TRAILER,
+
+ /* A trailer CR has been found - next state is CHUNK_TRAILER_POSTCR.
+ Next char must be a LF */
+ CHUNK_TRAILER_CR,
+
+ /* A trailer LF must be found now, otherwise CHUNKE_BAD_CHUNK will be
+ signalled If this is an empty trailer CHUNKE_STOP will be signalled.
+ Otherwise the trailer will be broadcasted via Curl_client_write() and the
+ next state will be CHUNK_TRAILER */
+ CHUNK_TRAILER_POSTCR,
+
+ CHUNK_LAST /* never use */
+
+} ChunkyState;
+
+typedef enum {
+ CHUNKE_STOP = -1,
+ CHUNKE_OK = 0,
+ CHUNKE_TOO_LONG_HEX = 1,
+ CHUNKE_ILLEGAL_HEX,
+ CHUNKE_BAD_CHUNK,
+ CHUNKE_WRITE_ERROR,
+ CHUNKE_STATE_ERROR,
+ CHUNKE_BAD_ENCODING,
+ CHUNKE_OUT_OF_MEMORY,
+ CHUNKE_LAST
+} CHUNKcode;
+
+struct Curl_chunker {
+ char hexbuffer[ MAXNUM_SIZE + 1];
+ int hexindex;
+ ChunkyState state;
+ size_t datasize;
+ size_t dataleft; /* untouched data amount at the end of the last buffer */
+};
+
+#endif /* HEADER_CURL_HTTP_CHUNKS_H */
+
diff --git a/libs/libcurl/src/http_digest.c b/libs/libcurl/src/http_digest.c
new file mode 100644
index 0000000000..f50f8033f9
--- /dev/null
+++ b/libs/libcurl/src/http_digest.c
@@ -0,0 +1,604 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+
+#include "urldata.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "curl_md5.h"
+#include "http_digest.h"
+#include "strtok.h"
+#include "curl_memory.h"
+#include "sslgen.h" /* for Curl_rand() */
+#include "non-ascii.h" /* included for Curl_convert_... prototypes */
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define MAX_VALUE_LENGTH 256
+#define MAX_CONTENT_LENGTH 1024
+
+static void digest_cleanup_one(struct digestdata *dig);
+
+/*
+ * Return 0 on success and then the buffers are filled in fine.
+ *
+ * Non-zero means failure to parse.
+ */
+static int get_pair(const char *str, char *value, char *content,
+ const char **endptr)
+{
+ int c;
+ bool starts_with_quote = FALSE;
+ bool escape = FALSE;
+
+ for(c=MAX_VALUE_LENGTH-1; (*str && (*str != '=') && c--); )
+ *value++ = *str++;
+ *value=0;
+
+ if('=' != *str++)
+ /* eek, no match */
+ return 1;
+
+ if('\"' == *str) {
+ /* this starts with a quote so it must end with one as well! */
+ str++;
+ starts_with_quote = TRUE;
+ }
+
+ for(c=MAX_CONTENT_LENGTH-1; *str && c--; str++) {
+ switch(*str) {
+ case '\\':
+ if(!escape) {
+ /* possibly the start of an escaped quote */
+ escape = TRUE;
+ *content++ = '\\'; /* even though this is an escape character, we still
+ store it as-is in the target buffer */
+ continue;
+ }
+ break;
+ case ',':
+ if(!starts_with_quote) {
+ /* this signals the end of the content if we didn't get a starting
+ quote and then we do "sloppy" parsing */
+ c=0; /* the end */
+ continue;
+ }
+ break;
+ case '\r':
+ case '\n':
+ /* end of string */
+ c=0;
+ continue;
+ case '\"':
+ if(!escape && starts_with_quote) {
+ /* end of string */
+ c=0;
+ continue;
+ }
+ break;
+ }
+ escape = FALSE;
+ *content++ = *str;
+ }
+ *content=0;
+
+ *endptr = str;
+
+ return 0; /* all is fine! */
+}
+
+/* Test example headers:
+
+WWW-Authenticate: Digest realm="testrealm", nonce="1053604598"
+Proxy-Authenticate: Digest realm="testrealm", nonce="1053604598"
+
+*/
+
+CURLdigest Curl_input_digest(struct connectdata *conn,
+ bool proxy,
+ const char *header) /* rest of the *-authenticate:
+ header */
+{
+ char *token = NULL;
+ char *tmp = NULL;
+ bool foundAuth = FALSE;
+ bool foundAuthInt = FALSE;
+ struct SessionHandle *data=conn->data;
+ bool before = FALSE; /* got a nonce before */
+ struct digestdata *d;
+
+ if(proxy) {
+ d = &data->state.proxydigest;
+ }
+ else {
+ d = &data->state.digest;
+ }
+
+ /* skip initial whitespaces */
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(checkprefix("Digest", header)) {
+ header += strlen("Digest");
+
+ /* If we already have received a nonce, keep that in mind */
+ if(d->nonce)
+ before = TRUE;
+
+ /* clear off any former leftovers and init to defaults */
+ digest_cleanup_one(d);
+
+ for(;;) {
+ char value[MAX_VALUE_LENGTH];
+ char content[MAX_CONTENT_LENGTH];
+
+ while(*header && ISSPACE(*header))
+ header++;
+
+ /* extract a value=content pair */
+ if(!get_pair(header, value, content, &header)) {
+ if(Curl_raw_equal(value, "nonce")) {
+ d->nonce = strdup(content);
+ if(!d->nonce)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(Curl_raw_equal(value, "stale")) {
+ if(Curl_raw_equal(content, "true")) {
+ d->stale = TRUE;
+ d->nc = 1; /* we make a new nonce now */
+ }
+ }
+ else if(Curl_raw_equal(value, "realm")) {
+ d->realm = strdup(content);
+ if(!d->realm)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(Curl_raw_equal(value, "opaque")) {
+ d->opaque = strdup(content);
+ if(!d->opaque)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(Curl_raw_equal(value, "qop")) {
+ char *tok_buf;
+ /* tokenize the list and choose auth if possible, use a temporary
+ clone of the buffer since strtok_r() ruins it */
+ tmp = strdup(content);
+ if(!tmp)
+ return CURLDIGEST_NOMEM;
+ token = strtok_r(tmp, ",", &tok_buf);
+ while(token != NULL) {
+ if(Curl_raw_equal(token, "auth")) {
+ foundAuth = TRUE;
+ }
+ else if(Curl_raw_equal(token, "auth-int")) {
+ foundAuthInt = TRUE;
+ }
+ token = strtok_r(NULL, ",", &tok_buf);
+ }
+ free(tmp);
+ /*select only auth o auth-int. Otherwise, ignore*/
+ if(foundAuth) {
+ d->qop = strdup("auth");
+ if(!d->qop)
+ return CURLDIGEST_NOMEM;
+ }
+ else if(foundAuthInt) {
+ d->qop = strdup("auth-int");
+ if(!d->qop)
+ return CURLDIGEST_NOMEM;
+ }
+ }
+ else if(Curl_raw_equal(value, "algorithm")) {
+ d->algorithm = strdup(content);
+ if(!d->algorithm)
+ return CURLDIGEST_NOMEM;
+ if(Curl_raw_equal(content, "MD5-sess"))
+ d->algo = CURLDIGESTALGO_MD5SESS;
+ else if(Curl_raw_equal(content, "MD5"))
+ d->algo = CURLDIGESTALGO_MD5;
+ else
+ return CURLDIGEST_BADALGO;
+ }
+ else {
+ /* unknown specifier, ignore it! */
+ }
+ }
+ else
+ break; /* we're done here */
+
+ /* pass all additional spaces here */
+ while(*header && ISSPACE(*header))
+ header++;
+ if(',' == *header)
+ /* allow the list to be comma-separated */
+ header++;
+ }
+ /* We had a nonce since before, and we got another one now without
+ 'stale=true'. This means we provided bad credentials in the previous
+ request */
+ if(before && !d->stale)
+ return CURLDIGEST_BAD;
+
+ /* We got this header without a nonce, that's a bad Digest line! */
+ if(!d->nonce)
+ return CURLDIGEST_BAD;
+ }
+ else
+ /* else not a digest, get out */
+ return CURLDIGEST_NONE;
+
+ return CURLDIGEST_FINE;
+}
+
+/* convert md5 chunk to RFC2617 (section 3.1.3) -suitable ascii string*/
+static void md5_to_ascii(unsigned char *source, /* 16 bytes */
+ unsigned char *dest) /* 33 bytes */
+{
+ int i;
+ for(i=0; i<16; i++)
+ 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,
+ const unsigned char *uripath)
+{
+ /* We have a Digest setup for this, use it! Now, to get all the details for
+ this sorted out, I must urge you dear friend to read up on the RFC2617
+ section 3.2.2, */
+ unsigned char md5buf[16]; /* 16 bytes/128 bits */
+ unsigned char request_digest[33];
+ unsigned char *md5this;
+ 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;
+ char **allocuserpwd;
+ size_t userlen;
+ const char *userp;
+ char *userp_quoted;
+ const char *passwdp;
+ struct auth *authp;
+
+ struct SessionHandle *data = conn->data;
+ struct digestdata *d;
+ CURLcode rc;
+/* The CURL_OUTPUT_DIGEST_CONV macro below is for non-ASCII machines.
+ It converts digest text to ASCII so the MD5 will be correct for
+ what ultimately goes over the network.
+*/
+#define CURL_OUTPUT_DIGEST_CONV(a, b) \
+ rc = Curl_convert_to_network(a, (char *)b, strlen((const char*)b)); \
+ if(rc != CURLE_OK) { \
+ free(b); \
+ return rc; \
+ }
+
+ if(proxy) {
+ d = &data->state.proxydigest;
+ allocuserpwd = &conn->allocptr.proxyuserpwd;
+ userp = conn->proxyuser;
+ passwdp = conn->proxypasswd;
+ authp = &data->state.authproxy;
+ }
+ else {
+ d = &data->state.digest;
+ allocuserpwd = &conn->allocptr.userpwd;
+ userp = conn->user;
+ passwdp = conn->passwd;
+ authp = &data->state.authhost;
+ }
+
+ Curl_safefree(*allocuserpwd);
+
+ /* not set means empty */
+ if(!userp)
+ userp="";
+
+ if(!passwdp)
+ passwdp="";
+
+ if(!d->nonce) {
+ authp->done = FALSE;
+ return CURLE_OK;
+ }
+ authp->done = TRUE;
+
+ if(!d->nc)
+ d->nc = 1;
+
+ if(!d->cnonce) {
+ 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);
+ if(rc)
+ return rc;
+ d->cnonce = cnonce;
+ }
+
+ /*
+ if the algorithm is "MD5" or unspecified (which then defaults to MD5):
+
+ A1 = unq(username-value) ":" unq(realm-value) ":" passwd
+
+ if the algorithm is "MD5-sess" then:
+
+ A1 = H( unq(username-value) ":" unq(realm-value) ":" passwd )
+ ":" unq(nonce-value) ":" unq(cnonce-value)
+ */
+
+ md5this = (unsigned char *)
+ aprintf("%s:%s:%s", userp, d->realm, passwdp);
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ Curl_safefree(md5this);
+ md5_to_ascii(md5buf, ha1);
+
+ if(d->algo == CURLDIGESTALGO_MD5SESS) {
+ /* nonce and cnonce are OUTSIDE the hash */
+ tmp = aprintf("%s:%s:%s", ha1, d->nonce, d->cnonce);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ CURL_OUTPUT_DIGEST_CONV(data, tmp); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, (unsigned char *)tmp);
+ Curl_safefree(tmp);
+ md5_to_ascii(md5buf, ha1);
+ }
+
+ /*
+ If the "qop" directive's value is "auth" or is unspecified, then A2 is:
+
+ A2 = Method ":" digest-uri-value
+
+ If the "qop" value is "auth-int", then A2 is:
+
+ A2 = Method ":" digest-uri-value ":" H(entity-body)
+
+ (The "Method" value is the HTTP request method as specified in section
+ 5.1.1 of RFC 2616)
+ */
+
+ /* So IE browsers < v7 cut off the URI part at the query part when they
+ evaluate the MD5 and some (IIS?) servers work with them so we may need to
+ do the Digest IE-style. Note that the different ways cause different MD5
+ sums to get sent.
+
+ Apache servers can be set to do the Digest IE-style automatically using
+ the BrowserMatch feature:
+ http://httpd.apache.org/docs/2.2/mod/mod_auth_digest.html#msie
+
+ Further details on Digest implementation differences:
+ http://www.fngtps.com/2006/09/http-authentication
+ */
+ if(authp->iestyle && ((tmp = strchr((char *)uripath, '?')) != NULL)) {
+ md5this = (unsigned char *)aprintf("%s:%.*s", request,
+ curlx_sztosi(tmp - (char *)uripath),
+ uripath);
+ }
+ else
+ md5this = (unsigned char *)aprintf("%s:%s", request, uripath);
+
+ 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(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ Curl_safefree(md5this);
+ md5_to_ascii(md5buf, ha2);
+
+ if(d->qop) {
+ md5this = (unsigned char *)aprintf("%s:%s:%08x:%s:%s:%s",
+ ha1,
+ d->nonce,
+ d->nc,
+ d->cnonce,
+ d->qop,
+ ha2);
+ }
+ else {
+ md5this = (unsigned char *)aprintf("%s:%s:%s",
+ ha1,
+ d->nonce,
+ ha2);
+ }
+ if(!md5this)
+ return CURLE_OUT_OF_MEMORY;
+
+ CURL_OUTPUT_DIGEST_CONV(data, md5this); /* convert on non-ASCII machines */
+ Curl_md5it(md5buf, md5this);
+ 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 =
+ aprintf( "%sAuthorization: Digest "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "cnonce=\"%s\", "
+ "nc=%08x, "
+ "qop=%s, "
+ "response=\"%s\"",
+ proxy?"Proxy-":"",
+ userp_quoted,
+ d->realm,
+ d->nonce,
+ uripath, /* this is the PATH part of the URL */
+ d->cnonce,
+ d->nc,
+ d->qop,
+ request_digest);
+
+ if(Curl_raw_equal(d->qop, "auth"))
+ d->nc++; /* The nc (from RFC) has to be a 8 hex digit number 0 padded
+ which tells to the server how many times you are using the
+ same nonce in the qop=auth mode. */
+ }
+ else {
+ *allocuserpwd =
+ aprintf( "%sAuthorization: Digest "
+ "username=\"%s\", "
+ "realm=\"%s\", "
+ "nonce=\"%s\", "
+ "uri=\"%s\", "
+ "response=\"%s\"",
+ proxy?"Proxy-":"",
+ 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;
+
+ /* Add optional fields */
+ if(d->opaque) {
+ /* append opaque */
+ tmp = aprintf("%s, opaque=\"%s\"", *allocuserpwd, d->opaque);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ free(*allocuserpwd);
+ *allocuserpwd = tmp;
+ }
+
+ if(d->algorithm) {
+ /* append algorithm */
+ tmp = aprintf("%s, algorithm=\"%s\"", *allocuserpwd, d->algorithm);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ free(*allocuserpwd);
+ *allocuserpwd = tmp;
+ }
+
+ /* append CRLF + zero (3 bytes) to the userpwd header */
+ userlen = strlen(*allocuserpwd);
+ tmp = realloc(*allocuserpwd, userlen + 3);
+ if(!tmp)
+ return CURLE_OUT_OF_MEMORY;
+ strcpy(&tmp[userlen], "\r\n"); /* append the data */
+ *allocuserpwd = tmp;
+
+ return CURLE_OK;
+}
+
+static void digest_cleanup_one(struct digestdata *d)
+{
+ 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 */
+ d->stale = FALSE; /* default means normal, not stale */
+}
+
+
+void Curl_digest_cleanup(struct SessionHandle *data)
+{
+ digest_cleanup_one(&data->state.digest);
+ digest_cleanup_one(&data->state.proxydigest);
+}
+
+#endif
diff --git a/libs/libcurl/src/http_digest.h b/libs/libcurl/src/http_digest.h
new file mode 100644
index 0000000000..c6a4e91610
--- /dev/null
+++ b/libs/libcurl/src/http_digest.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_HTTP_DIGEST_H
+#define HEADER_CURL_HTTP_DIGEST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+typedef enum {
+ CURLDIGEST_NONE, /* not a digest */
+ CURLDIGEST_BAD, /* a digest, but one we don't like */
+ CURLDIGEST_BADALGO, /* unsupported algorithm requested */
+ CURLDIGEST_NOMEM,
+ CURLDIGEST_FINE, /* a digest we act on */
+
+ CURLDIGEST_LAST /* last entry in this enum, don't use */
+} CURLdigest;
+
+enum {
+ CURLDIGESTALGO_MD5,
+ CURLDIGESTALGO_MD5SESS
+};
+
+/* this is for digest header input */
+CURLdigest Curl_input_digest(struct connectdata *conn,
+ bool proxy, const char *header);
+
+/* this is for creating digest header output */
+CURLcode Curl_output_digest(struct connectdata *conn,
+ bool proxy,
+ const unsigned char *request,
+ const unsigned char *uripath);
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
+void Curl_digest_cleanup(struct SessionHandle *data);
+#else
+#define Curl_digest_cleanup(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_HTTP_DIGEST_H */
diff --git a/libs/libcurl/src/http_negotiate.c b/libs/libcurl/src/http_negotiate.c
new file mode 100644
index 0000000000..9b981b3327
--- /dev/null
+++ b/libs/libcurl/src/http_negotiate.c
@@ -0,0 +1,388 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_GSSAPI
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#define NCOMPAT 1
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h"
+#include "sendf.h"
+#include "curl_gssapi.h"
+#include "rawstr.h"
+#include "curl_base64.h"
+#include "http_negotiate.h"
+#include "curl_memory.h"
+#include "url.h"
+
+#ifdef HAVE_SPNEGO
+# include <spnegohelp.h>
+# ifdef USE_SSLEAY
+# ifdef USE_OPENSSL
+# include <openssl/objects.h>
+# else
+# include <objects.h>
+# endif
+# else
+# error "Can't compile SPNEGO support without OpenSSL."
+# endif
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static int
+get_gss_name(struct connectdata *conn, bool proxy, gss_name_t *server)
+{
+ struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+ &conn->data->state.negotiate;
+ OM_uint32 major_status, minor_status;
+ gss_buffer_desc token = GSS_C_EMPTY_BUFFER;
+ char name[2048];
+ const char* service;
+
+ /* GSSAPI implementation by Globus (known as GSI) requires the name to be
+ of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
+ of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
+ Change following lines if you want to use GSI */
+
+ /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name */
+
+ if(neg_ctx->gss)
+ service = "KHTTP";
+ else
+ service = "HTTP";
+
+ token.length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name :
+ conn->host.name) + 1;
+ if(token.length + 1 > sizeof(name))
+ return EMSGSIZE;
+
+ snprintf(name, sizeof(name), "%s@%s", service, proxy ? conn->proxy.name :
+ conn->host.name);
+
+ token.value = (void *) name;
+ major_status = gss_import_name(&minor_status,
+ &token,
+ GSS_C_NT_HOSTBASED_SERVICE,
+ server);
+
+ return GSS_ERROR(major_status) ? -1 : 0;
+}
+
+static void
+log_gss_error(struct connectdata *conn, OM_uint32 error_status,
+ const char *prefix)
+{
+ OM_uint32 maj_stat, min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ char buf[1024];
+ size_t len;
+
+ snprintf(buf, sizeof(buf), "%s", prefix);
+ len = strlen(buf);
+ do {
+ maj_stat = gss_display_status(&min_stat,
+ error_status,
+ GSS_C_MECH_CODE,
+ GSS_C_NO_OID,
+ &msg_ctx,
+ &status_string);
+ if(sizeof(buf) > len + status_string.length + 1) {
+ snprintf(buf + len, sizeof(buf) - len,
+ ": %s", (char*) status_string.value);
+ len += status_string.length;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ } while(!GSS_ERROR(maj_stat) && msg_ctx != 0);
+
+ infof(conn->data, "%s\n", buf);
+}
+
+/* returning zero (0) means success, everything else is treated as "failure"
+ with no care exactly what the failure was */
+int Curl_input_negotiate(struct connectdata *conn, bool proxy,
+ const char *header)
+{
+ struct SessionHandle *data = conn->data;
+ struct negotiatedata *neg_ctx = proxy?&data->state.proxyneg:
+ &data->state.negotiate;
+ OM_uint32 major_status, minor_status, discard_st;
+ gss_buffer_desc input_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc output_token = GSS_C_EMPTY_BUFFER;
+ int ret;
+ size_t len;
+ size_t rawlen = 0;
+ bool gss;
+ const char* protocol;
+ CURLcode error;
+
+ while(*header && ISSPACE(*header))
+ header++;
+ if(checkprefix("GSS-Negotiate", header)) {
+ protocol = "GSS-Negotiate";
+ gss = TRUE;
+ }
+ else if(checkprefix("Negotiate", header)) {
+ protocol = "Negotiate";
+ gss = FALSE;
+ }
+ else
+ return -1;
+
+ if(neg_ctx->context) {
+ if(neg_ctx->gss != gss) {
+ return -1;
+ }
+ }
+ else {
+ neg_ctx->protocol = protocol;
+ neg_ctx->gss = gss;
+ }
+
+ if(neg_ctx->context && neg_ctx->status == GSS_S_COMPLETE) {
+ /* We finished successfully our part of authentication, but server
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
+ Curl_cleanup_negotiate(data);
+ return -1;
+ }
+
+ if(neg_ctx->server_name == NULL &&
+ (ret = get_gss_name(conn, proxy, &neg_ctx->server_name)))
+ return ret;
+
+ header += strlen(neg_ctx->protocol);
+ while(*header && ISSPACE(*header))
+ header++;
+
+ len = strlen(header);
+ if(len > 0) {
+ error = Curl_base64_decode(header,
+ (unsigned char **)&input_token.value, &rawlen);
+ if(error || rawlen == 0)
+ return -1;
+ input_token.length = rawlen;
+
+ DEBUGASSERT(input_token.value != NULL);
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+ if(checkprefix("Negotiate", header)) {
+ unsigned char *spnegoToken = NULL;
+ size_t spnegoTokenLength = 0;
+ gss_buffer_desc mechToken = GSS_C_EMPTY_BUFFER;
+
+ spnegoToken = malloc(input_token.length);
+ if(spnegoToken == NULL) {
+ Curl_safefree(input_token.value);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(spnegoToken, input_token.value, input_token.length);
+ spnegoTokenLength = input_token.length;
+
+ if(!parseSpnegoTargetToken(spnegoToken,
+ spnegoTokenLength,
+ NULL,
+ NULL,
+ (unsigned char**)&mechToken.value,
+ &mechToken.length,
+ NULL,
+ NULL)) {
+ Curl_safefree(spnegoToken);
+ infof(data, "Parse SPNEGO Target Token failed\n");
+ }
+ else if(!mechToken.value || !mechToken.length) {
+ Curl_safefree(spnegoToken);
+ if(mechToken.value)
+ gss_release_buffer(&discard_st, &mechToken);
+ infof(data, "Parse SPNEGO Target Token succeeded (NULL token)\n");
+ }
+ else {
+ Curl_safefree(spnegoToken);
+ Curl_safefree(input_token.value);
+ input_token.value = malloc(mechToken.length);
+ if(input_token.value == NULL) {
+ gss_release_buffer(&discard_st, &mechToken);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(input_token.value, mechToken.value, mechToken.length);
+ input_token.length = mechToken.length;
+ gss_release_buffer(&discard_st, &mechToken);
+ infof(data, "Parse SPNEGO Target Token succeeded\n");
+ }
+ }
+#endif
+ }
+
+ major_status = Curl_gss_init_sec_context(data,
+ &minor_status,
+ &neg_ctx->context,
+ neg_ctx->server_name,
+ GSS_C_NO_CHANNEL_BINDINGS,
+ &input_token,
+ &output_token,
+ NULL);
+ Curl_safefree(input_token.value);
+
+ neg_ctx->status = major_status;
+ if(GSS_ERROR(major_status)) {
+ if(output_token.value)
+ gss_release_buffer(&discard_st, &output_token);
+ log_gss_error(conn, minor_status, "gss_init_sec_context() failed: ");
+ return -1;
+ }
+
+ if(!output_token.value || !output_token.length) {
+ if(output_token.value)
+ gss_release_buffer(&discard_st, &output_token);
+ return -1;
+ }
+
+ neg_ctx->output_token = output_token;
+ return 0;
+}
+
+
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
+{
+ struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+ &conn->data->state.negotiate;
+ char *encoded = NULL;
+ size_t len = 0;
+ char *userp;
+ CURLcode error;
+ OM_uint32 discard_st;
+
+#ifdef HAVE_SPNEGO /* Handle SPNEGO */
+ if(checkprefix("Negotiate", neg_ctx->protocol)) {
+ ASN1_OBJECT *object = NULL;
+ unsigned char *responseToken = NULL;
+ size_t responseTokenLength = 0;
+ gss_buffer_desc spnegoToken = GSS_C_EMPTY_BUFFER;
+
+ responseToken = malloc(neg_ctx->output_token.length);
+ if(responseToken == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(responseToken, neg_ctx->output_token.value,
+ neg_ctx->output_token.length);
+ responseTokenLength = neg_ctx->output_token.length;
+
+ object = OBJ_txt2obj("1.2.840.113554.1.2.2", 1);
+ if(!object) {
+ Curl_safefree(responseToken);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!makeSpnegoInitialToken(object,
+ responseToken,
+ responseTokenLength,
+ (unsigned char**)&spnegoToken.value,
+ &spnegoToken.length)) {
+ Curl_safefree(responseToken);
+ ASN1_OBJECT_free(object);
+ infof(conn->data, "Make SPNEGO Initial Token failed\n");
+ }
+ else if(!spnegoToken.value || !spnegoToken.length) {
+ Curl_safefree(responseToken);
+ ASN1_OBJECT_free(object);
+ if(spnegoToken.value)
+ gss_release_buffer(&discard_st, &spnegoToken);
+ infof(conn->data, "Make SPNEGO Initial Token succeeded (NULL token)\n");
+ }
+ else {
+ Curl_safefree(responseToken);
+ ASN1_OBJECT_free(object);
+ gss_release_buffer(&discard_st, &neg_ctx->output_token);
+ neg_ctx->output_token.value = spnegoToken.value;
+ neg_ctx->output_token.length = spnegoToken.length;
+ infof(conn->data, "Make SPNEGO Initial Token succeeded\n");
+ }
+ }
+#endif
+ error = Curl_base64_encode(conn->data,
+ neg_ctx->output_token.value,
+ neg_ctx->output_token.length,
+ &encoded, &len);
+ if(error) {
+ gss_release_buffer(&discard_st, &neg_ctx->output_token);
+ neg_ctx->output_token.value = NULL;
+ neg_ctx->output_token.length = 0;
+ return error;
+ }
+
+ if(!encoded || !len) {
+ gss_release_buffer(&discard_st, &neg_ctx->output_token);
+ neg_ctx->output_token.value = NULL;
+ neg_ctx->output_token.length = 0;
+ return CURLE_REMOTE_ACCESS_DENIED;
+ }
+
+ userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
+ neg_ctx->protocol, encoded);
+ if(proxy) {
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = userp;
+ }
+ else {
+ Curl_safefree(conn->allocptr.userpwd);
+ conn->allocptr.userpwd = userp;
+ }
+
+ Curl_safefree(encoded);
+ Curl_cleanup_negotiate(conn->data);
+
+ return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+static void cleanup(struct negotiatedata *neg_ctx)
+{
+ OM_uint32 minor_status;
+ if(neg_ctx->context != GSS_C_NO_CONTEXT)
+ gss_delete_sec_context(&minor_status, &neg_ctx->context, GSS_C_NO_BUFFER);
+
+ if(neg_ctx->output_token.value)
+ gss_release_buffer(&minor_status, &neg_ctx->output_token);
+
+ if(neg_ctx->server_name != GSS_C_NO_NAME)
+ gss_release_name(&minor_status, &neg_ctx->server_name);
+
+ memset(neg_ctx, 0, sizeof(*neg_ctx));
+}
+
+void Curl_cleanup_negotiate(struct SessionHandle *data)
+{
+ cleanup(&data->state.negotiate);
+ cleanup(&data->state.proxyneg);
+}
+
+
+#endif
+#endif
diff --git a/libs/libcurl/src/http_negotiate.h b/libs/libcurl/src/http_negotiate.h
new file mode 100644
index 0000000000..e584d76fcc
--- /dev/null
+++ b/libs/libcurl/src/http_negotiate.h
@@ -0,0 +1,42 @@
+#ifndef HEADER_CURL_HTTP_NEGOTIATE_H
+#define HEADER_CURL_HTTP_NEGOTIATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_HTTP_NEGOTIATE
+
+/* this is for Negotiate header input */
+int Curl_input_negotiate(struct connectdata *conn, bool proxy,
+ const char *header);
+
+/* this is for creating Negotiate header output */
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy);
+
+void Curl_cleanup_negotiate(struct SessionHandle *data);
+
+#ifdef USE_WINDOWS_SSPI
+#define GSS_ERROR(status) (status & 0x80000000)
+#endif
+
+#endif /* USE_HTTP_NEGOTIATE */
+
+#endif /* HEADER_CURL_HTTP_NEGOTIATE_H */
diff --git a/libs/libcurl/src/http_negotiate_sspi.c b/libs/libcurl/src/http_negotiate_sspi.c
new file mode 100644
index 0000000000..1381d5292d
--- /dev/null
+++ b/libs/libcurl/src/http_negotiate_sspi.c
@@ -0,0 +1,308 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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_WINDOWS_SSPI
+
+#ifndef CURL_DISABLE_HTTP
+
+#include "urldata.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "warnless.h"
+#include "curl_base64.h"
+#include "http_negotiate.h"
+#include "curl_memory.h"
+#include "curl_multibyte.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static int
+get_gss_name(struct connectdata *conn, bool proxy,
+ struct negotiatedata *neg_ctx)
+{
+ const char* service;
+ size_t length;
+
+ if(proxy && !conn->proxy.name)
+ /* proxy auth requested but no given proxy name, error out! */
+ return -1;
+
+ /* GSSAPI implementation by Globus (known as GSI) requires the name to be
+ of form "<service>/<fqdn>" instead of <service>@<fqdn> (ie. slash instead
+ of at-sign). Also GSI servers are often identified as 'host' not 'khttp'.
+ Change following lines if you want to use GSI */
+
+ /* IIS uses the <service>@<fqdn> form but uses 'http' as the service name,
+ and SSPI then generates an NTLM token. When using <service>/<fqdn> a
+ Kerberos token is generated. */
+
+ if(neg_ctx->gss)
+ service = "KHTTP";
+ else
+ service = "HTTP";
+
+ length = strlen(service) + 1 + strlen(proxy ? conn->proxy.name :
+ conn->host.name) + 1;
+ if(length + 1 > sizeof(neg_ctx->server_name))
+ return EMSGSIZE;
+
+ snprintf(neg_ctx->server_name, sizeof(neg_ctx->server_name), "%s/%s",
+ service, proxy ? conn->proxy.name : conn->host.name);
+
+ return 0;
+}
+
+/* returning zero (0) means success, everything else is treated as "failure"
+ with no care exactly what the failure was */
+int Curl_input_negotiate(struct connectdata *conn, bool proxy,
+ const char *header)
+{
+ struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+ &conn->data->state.negotiate;
+ BYTE *input_token = 0;
+ SecBufferDesc out_buff_desc;
+ SecBuffer out_sec_buff;
+ SecBufferDesc in_buff_desc;
+ SecBuffer in_sec_buff;
+ unsigned long context_attributes;
+ TimeStamp lifetime;
+ TCHAR *sname;
+ int ret;
+ size_t len = 0, input_token_len = 0;
+ bool gss = FALSE;
+ const char* protocol;
+ CURLcode error;
+
+ while(*header && ISSPACE(*header))
+ header++;
+
+ if(checkprefix("GSS-Negotiate", header)) {
+ protocol = "GSS-Negotiate";
+ gss = TRUE;
+ }
+ else if(checkprefix("Negotiate", header)) {
+ protocol = "Negotiate";
+ gss = FALSE;
+ }
+ else
+ return -1;
+
+ if(neg_ctx->context) {
+ if(neg_ctx->gss != gss) {
+ return -1;
+ }
+ }
+ else {
+ neg_ctx->protocol = protocol;
+ neg_ctx->gss = gss;
+ }
+
+ if(neg_ctx->context && neg_ctx->status == SEC_E_OK) {
+ /* We finished successfully our part of authentication, but server
+ * rejected it (since we're again here). Exit with an error since we
+ * can't invent anything better */
+ Curl_cleanup_negotiate(conn->data);
+ return -1;
+ }
+
+ if(0 == strlen(neg_ctx->server_name)) {
+ ret = get_gss_name(conn, proxy, neg_ctx);
+ if(ret)
+ return ret;
+ }
+
+ if(!neg_ctx->output_token) {
+ PSecPkgInfo SecurityPackage;
+ ret = s_pSecFn->QuerySecurityPackageInfo((TCHAR *) TEXT("Negotiate"),
+ &SecurityPackage);
+ if(ret != SEC_E_OK)
+ return -1;
+
+ /* Allocate input and output buffers according to the max token size
+ as indicated by the security package */
+ neg_ctx->max_token_length = SecurityPackage->cbMaxToken;
+ neg_ctx->output_token = malloc(neg_ctx->max_token_length);
+ s_pSecFn->FreeContextBuffer(SecurityPackage);
+ }
+
+ /* Obtain the input token, if any */
+ header += strlen(neg_ctx->protocol);
+ while(*header && ISSPACE(*header))
+ header++;
+
+ len = strlen(header);
+ if(!len) {
+ /* first call in a new negotation, we have to acquire credentials,
+ and allocate memory for the context */
+
+ neg_ctx->credentials = malloc(sizeof(CredHandle));
+ neg_ctx->context = malloc(sizeof(CtxtHandle));
+
+ if(!neg_ctx->credentials || !neg_ctx->context)
+ return -1;
+
+ neg_ctx->status =
+ s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT("Negotiate"),
+ SECPKG_CRED_OUTBOUND, NULL, NULL,
+ NULL, NULL, neg_ctx->credentials,
+ &lifetime);
+ if(neg_ctx->status != SEC_E_OK)
+ return -1;
+ }
+ else {
+ input_token = malloc(neg_ctx->max_token_length);
+ if(!input_token)
+ return -1;
+
+ error = Curl_base64_decode(header,
+ (unsigned char **)&input_token,
+ &input_token_len);
+ if(error || input_token_len == 0)
+ return -1;
+ }
+
+ /* prepare the output buffers, and input buffers if present */
+ out_buff_desc.ulVersion = 0;
+ out_buff_desc.cBuffers = 1;
+ out_buff_desc.pBuffers = &out_sec_buff;
+
+ out_sec_buff.cbBuffer = curlx_uztoul(neg_ctx->max_token_length);
+ out_sec_buff.BufferType = SECBUFFER_TOKEN;
+ out_sec_buff.pvBuffer = neg_ctx->output_token;
+
+
+ if(input_token) {
+ in_buff_desc.ulVersion = 0;
+ in_buff_desc.cBuffers = 1;
+ in_buff_desc.pBuffers = &in_sec_buff;
+
+ in_sec_buff.cbBuffer = curlx_uztoul(input_token_len);
+ in_sec_buff.BufferType = SECBUFFER_TOKEN;
+ in_sec_buff.pvBuffer = input_token;
+ }
+
+ sname = Curl_convert_UTF8_to_tchar(neg_ctx->server_name);
+ if(!sname)
+ return CURLE_OUT_OF_MEMORY;
+
+ neg_ctx->status = s_pSecFn->InitializeSecurityContext(
+ neg_ctx->credentials,
+ input_token ? neg_ctx->context : 0,
+ sname,
+ ISC_REQ_CONFIDENTIALITY,
+ 0,
+ SECURITY_NATIVE_DREP,
+ input_token ? &in_buff_desc : 0,
+ 0,
+ neg_ctx->context,
+ &out_buff_desc,
+ &context_attributes,
+ &lifetime);
+
+ Curl_unicodefree(sname);
+
+ if(GSS_ERROR(neg_ctx->status))
+ return -1;
+
+ if(neg_ctx->status == SEC_I_COMPLETE_NEEDED ||
+ neg_ctx->status == SEC_I_COMPLETE_AND_CONTINUE) {
+ neg_ctx->status = s_pSecFn->CompleteAuthToken(neg_ctx->context,
+ &out_buff_desc);
+ if(GSS_ERROR(neg_ctx->status))
+ return -1;
+ }
+
+ neg_ctx->output_token_length = out_sec_buff.cbBuffer;
+
+ return 0;
+}
+
+
+CURLcode Curl_output_negotiate(struct connectdata *conn, bool proxy)
+{
+ struct negotiatedata *neg_ctx = proxy?&conn->data->state.proxyneg:
+ &conn->data->state.negotiate;
+ char *encoded = NULL;
+ size_t len = 0;
+ char *userp;
+ CURLcode error;
+
+ error = Curl_base64_encode(conn->data,
+ (const char*)neg_ctx->output_token,
+ neg_ctx->output_token_length,
+ &encoded, &len);
+ if(error)
+ return error;
+
+ if(len == 0)
+ return CURLE_REMOTE_ACCESS_DENIED;
+
+ userp = aprintf("%sAuthorization: %s %s\r\n", proxy ? "Proxy-" : "",
+ neg_ctx->protocol, encoded);
+
+ if(proxy)
+ conn->allocptr.proxyuserpwd = userp;
+ else
+ conn->allocptr.userpwd = userp;
+ free(encoded);
+ Curl_cleanup_negotiate (conn->data);
+ return (userp == NULL) ? CURLE_OUT_OF_MEMORY : CURLE_OK;
+}
+
+static void cleanup(struct negotiatedata *neg_ctx)
+{
+ if(neg_ctx->context) {
+ s_pSecFn->DeleteSecurityContext(neg_ctx->context);
+ free(neg_ctx->context);
+ neg_ctx->context = 0;
+ }
+
+ if(neg_ctx->credentials) {
+ s_pSecFn->FreeCredentialsHandle(neg_ctx->credentials);
+ free(neg_ctx->credentials);
+ neg_ctx->credentials = 0;
+ }
+
+ if(neg_ctx->output_token) {
+ free(neg_ctx->output_token);
+ neg_ctx->output_token = 0;
+ }
+
+ neg_ctx->max_token_length = 0;
+}
+
+void Curl_cleanup_negotiate(struct SessionHandle *data)
+{
+ cleanup(&data->state.negotiate);
+ cleanup(&data->state.proxyneg);
+}
+
+
+#endif
+#endif
diff --git a/libs/libcurl/src/http_proxy.c b/libs/libcurl/src/http_proxy.c
new file mode 100644
index 0000000000..6a555525d1
--- /dev/null
+++ b/libs/libcurl/src/http_proxy.c
@@ -0,0 +1,571 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "http_proxy.h"
+#include "sendf.h"
+#include "http.h"
+#include "url.h"
+#include "select.h"
+#include "rawstr.h"
+#include "progress.h"
+#include "non-ascii.h"
+#include "connect.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curlx.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+CURLcode Curl_proxy_connect(struct connectdata *conn)
+{
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy) {
+#ifndef CURL_DISABLE_PROXY
+ /* for [protocol] tunneled through HTTP proxy */
+ struct HTTP http_proxy;
+ void *prot_save;
+ CURLcode result;
+
+ /* BLOCKING */
+ /* We want "seamless" operations through HTTP proxy tunnel */
+
+ /* Curl_proxyCONNECT is based on a pointer to a struct HTTP at the
+ * member conn->proto.http; we want [protocol] through HTTP and we have
+ * to change the member temporarily for connecting to the HTTP
+ * proxy. After Curl_proxyCONNECT we have to set back the member to the
+ * original pointer
+ *
+ * This function might be called several times in the multi interface case
+ * if the proxy's CONNTECT response is not instant.
+ */
+ prot_save = conn->data->req.protop;
+ memset(&http_proxy, 0, sizeof(http_proxy));
+ conn->data->req.protop = &http_proxy;
+ conn->bits.close = FALSE;
+ result = Curl_proxyCONNECT(conn, FIRSTSOCKET,
+ conn->host.name, conn->remote_port);
+ conn->data->req.protop = prot_save;
+ if(CURLE_OK != result)
+ return result;
+#else
+ return CURLE_NOT_BUILT_IN;
+#endif
+ }
+ /* no HTTP tunnel proxy, just return */
+ return CURLE_OK;
+}
+
+/*
+ * Curl_proxyCONNECT() requires that we're connected to a HTTP proxy. This
+ * function will issue the necessary commands to get a seamless tunnel through
+ * this proxy. After that, the socket can be used just as a normal socket.
+ */
+
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+ int sockindex,
+ const char *hostname,
+ unsigned short remote_port)
+{
+ int subversion=0;
+ struct SessionHandle *data=conn->data;
+ struct SingleRequest *k = &data->req;
+ CURLcode result;
+ long timeout =
+ data->set.timeout?data->set.timeout:PROXY_TIMEOUT; /* in milliseconds */
+ curl_socket_t tunnelsocket = conn->sock[sockindex];
+ curl_off_t cl=0;
+ bool closeConnection = FALSE;
+ bool chunked_encoding = FALSE;
+ long check;
+
+#define SELECT_OK 0
+#define SELECT_ERROR 1
+#define SELECT_TIMEOUT 2
+ int error = SELECT_OK;
+
+ if(conn->tunnel_state[sockindex] == TUNNEL_COMPLETE)
+ return CURLE_OK; /* CONNECT is already completed */
+
+ conn->bits.proxy_connect_closed = FALSE;
+
+ do {
+ if(TUNNEL_INIT == conn->tunnel_state[sockindex]) {
+ /* BEGIN CONNECT PHASE */
+ char *host_port;
+ Curl_send_buffer *req_buffer;
+
+ infof(data, "Establish HTTP proxy tunnel to %s:%hu\n",
+ hostname, remote_port);
+
+ if(data->req.newurl) {
+ /* This only happens if we've looped here due to authentication
+ reasons, and we don't really use the newly cloned URL here
+ then. Just free() it. */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ }
+
+ /* initialize a dynamic send-buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ host_port = aprintf("%s:%hu", hostname, remote_port);
+ if(!host_port) {
+ free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Setup the proxy-authorization header, if any */
+ result = Curl_http_output_auth(conn, "CONNECT", host_port, TRUE);
+
+ free(host_port);
+
+ if(CURLE_OK == result) {
+ char *host=(char *)"";
+ const char *proxyconn="";
+ const char *useragent="";
+ const char *http = (conn->proxytype == CURLPROXY_HTTP_1_0) ?
+ "1.0" : "1.1";
+ char *hostheader= /* host:port with IPv6 support */
+ aprintf("%s%s%s:%hu", conn->bits.ipv6_ip?"[":"",
+ hostname, conn->bits.ipv6_ip?"]":"",
+ remote_port);
+ if(!hostheader) {
+ free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!Curl_checkheaders(data, "Host:")) {
+ host = aprintf("Host: %s\r\n", hostheader);
+ if(!host) {
+ free(hostheader);
+ free(req_buffer);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+ if(!Curl_checkheaders(data, "Proxy-Connection:"))
+ proxyconn = "Proxy-Connection: Keep-Alive\r\n";
+
+ if(!Curl_checkheaders(data, "User-Agent:") &&
+ data->set.str[STRING_USERAGENT])
+ useragent = conn->allocptr.uagent;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "CONNECT %s HTTP/%s\r\n"
+ "%s" /* Host: */
+ "%s" /* Proxy-Authorization */
+ "%s" /* User-Agent */
+ "%s", /* Proxy-Connection */
+ hostheader,
+ http,
+ host,
+ conn->allocptr.proxyuserpwd?
+ conn->allocptr.proxyuserpwd:"",
+ useragent,
+ proxyconn);
+
+ if(host && *host)
+ free(host);
+ free(hostheader);
+
+ if(CURLE_OK == result)
+ result = Curl_add_custom_headers(conn, req_buffer);
+
+ if(CURLE_OK == result)
+ /* CRLF terminate the request */
+ result = Curl_add_bufferf(req_buffer, "\r\n");
+
+ if(CURLE_OK == result) {
+ /* Send the connect request to the proxy */
+ /* BLOCKING */
+ result =
+ Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, sockindex);
+ }
+ req_buffer = NULL;
+ if(result)
+ failf(data, "Failed sending CONNECT to proxy");
+ }
+
+ Curl_safefree(req_buffer);
+ if(result)
+ return result;
+
+ conn->tunnel_state[sockindex] = TUNNEL_CONNECT;
+
+ /* now we've issued the CONNECT and we're waiting to hear back, return
+ and get called again polling-style */
+ return CURLE_OK;
+
+ } /* END CONNECT PHASE */
+
+ { /* BEGIN NEGOTIATION PHASE */
+ size_t nread; /* total size read */
+ int perline; /* count bytes per line */
+ int keepon=TRUE;
+ ssize_t gotbytes;
+ char *ptr;
+ char *line_start;
+
+ ptr=data->state.buffer;
+ line_start = ptr;
+
+ nread=0;
+ perline=0;
+ keepon=TRUE;
+
+ while((nread<BUFSIZE) && (keepon && !error)) {
+
+ /* if timeout is requested, find out how much remaining time we have */
+ check = timeout - /* timeout time */
+ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+ if(check <= 0) {
+ failf(data, "Proxy CONNECT aborted due to timeout");
+ error = SELECT_TIMEOUT; /* already too little time */
+ break;
+ }
+
+ /* loop every second at least, less if the timeout is near */
+ switch (Curl_socket_ready(tunnelsocket, CURL_SOCKET_BAD,
+ check<1000L?check:1000)) {
+ case -1: /* select() error, stop reading */
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted due to select/poll error");
+ break;
+ case 0: /* timeout */
+ break;
+ default:
+ DEBUGASSERT(ptr+BUFSIZE-nread <= data->state.buffer+BUFSIZE+1);
+ result = Curl_read(conn, tunnelsocket, ptr, BUFSIZE-nread,
+ &gotbytes);
+ if(result==CURLE_AGAIN)
+ continue; /* go loop yourself */
+ else if(result)
+ keepon = FALSE;
+ else if(gotbytes <= 0) {
+ keepon = FALSE;
+ if(data->set.proxyauth && data->state.authproxy.avail) {
+ /* proxy auth was requested and there was proxy auth available,
+ then deem this as "mere" proxy disconnect */
+ conn->bits.proxy_connect_closed = TRUE;
+ }
+ else {
+ error = SELECT_ERROR;
+ failf(data, "Proxy CONNECT aborted");
+ }
+ }
+ else {
+ /*
+ * We got a whole chunk of data, which can be anything from one
+ * byte to a set of lines and possibly just a piece of the last
+ * line.
+ */
+ int i;
+
+ nread += gotbytes;
+
+ if(keepon > TRUE) {
+ /* This means we are currently ignoring a response-body */
+
+ nread = 0; /* make next read start over in the read buffer */
+ ptr=data->state.buffer;
+ if(cl) {
+ /* A Content-Length based body: simply count down the counter
+ and make sure to break out of the loop when we're done! */
+ cl -= gotbytes;
+ if(cl<=0) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ else {
+ /* chunked-encoded body, so we need to do the chunked dance
+ properly to know when the end of the body is reached */
+ CHUNKcode r;
+ ssize_t tookcareof=0;
+
+ /* now parse the chunked piece of data so that we can
+ properly tell when the stream ends */
+ r = Curl_httpchunk_read(conn, ptr, gotbytes, &tookcareof);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE\n");
+ keepon = FALSE;
+ /* we did the full CONNECT treatment, go COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ }
+ else
+ infof(data, "Read %zd bytes of chunk, continue\n",
+ tookcareof);
+ }
+ }
+ else
+ for(i = 0; i < gotbytes; ptr++, i++) {
+ perline++; /* amount of bytes in this line so far */
+ if(*ptr == 0x0a) {
+ char letter;
+ int writetype;
+
+ /* convert from the network encoding */
+ result = Curl_convert_from_network(data, line_start,
+ perline);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(result)
+ return result;
+
+ /* output debug if that is requested */
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ line_start, (size_t)perline, conn);
+
+ /* send the header to the callback */
+ writetype = CLIENTWRITE_HEADER;
+ if(data->set.include_header)
+ writetype |= CLIENTWRITE_BODY;
+
+ result = Curl_client_write(conn, writetype, line_start,
+ perline);
+
+ data->info.header_size += (long)perline;
+ data->req.headerbytecount += (long)perline;
+
+ if(result)
+ return result;
+
+ /* Newlines are CRLF, so the CR is ignored as the line isn't
+ really terminated until the LF comes. Treat a following CR
+ as end-of-headers as well.*/
+
+ if(('\r' == line_start[0]) ||
+ ('\n' == line_start[0])) {
+ /* end of response-headers from the proxy */
+ nread = 0; /* make next read start over in the read
+ buffer */
+ ptr=data->state.buffer;
+ if((407 == k->httpcode) && !data->state.authproblem) {
+ /* If we get a 407 response code with content length
+ when we have no auth problem, we must ignore the
+ whole response-body */
+ keepon = 2;
+
+ if(cl) {
+
+ infof(data, "Ignore %" FORMAT_OFF_T
+ " bytes of response-body\n", cl);
+ /* remove the remaining chunk of what we already
+ read */
+ cl -= (gotbytes - i);
+
+ if(cl<=0)
+ /* if the whole thing was already read, we are done!
+ */
+ keepon=FALSE;
+ }
+ else if(chunked_encoding) {
+ CHUNKcode r;
+ /* We set ignorebody true here since the chunked
+ decoder function will acknowledge that. Pay
+ attention so that this is cleared again when this
+ function returns! */
+ k->ignorebody = TRUE;
+ infof(data, "%zd bytes of chunk left\n", gotbytes-i);
+
+ if(line_start[1] == '\n') {
+ /* this can only be a LF if the letter at index 0
+ was a CR */
+ line_start++;
+ i++;
+ }
+
+ /* now parse the chunked piece of data so that we can
+ properly tell when the stream ends */
+ r = Curl_httpchunk_read(conn, line_start+1,
+ gotbytes -i, &gotbytes);
+ if(r == CHUNKE_STOP) {
+ /* we're done reading chunks! */
+ infof(data, "chunk reading DONE\n");
+ keepon = FALSE;
+ /* we did the full CONNECT treatment, go to
+ COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ }
+ else
+ infof(data, "Read %zd bytes of chunk, continue\n",
+ gotbytes);
+ }
+ else {
+ /* without content-length or chunked encoding, we
+ can't keep the connection alive since the close is
+ the end signal so we bail out at once instead */
+ keepon=FALSE;
+ }
+ }
+ else {
+ keepon = FALSE;
+ if(200 == data->info.httpproxycode) {
+ if(gotbytes - (i+1))
+ failf(data, "Proxy CONNECT followed by %zd bytes "
+ "of opaque data. Data ignored (known bug #39)",
+ gotbytes - (i+1));
+ }
+ }
+ /* we did the full CONNECT treatment, go to COMPLETE */
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+ break; /* breaks out of for-loop, not switch() */
+ }
+
+ /* keep a backup of the position we are about to blank */
+ letter = line_start[perline];
+ line_start[perline]=0; /* zero terminate the buffer */
+ if((checkprefix("WWW-Authenticate:", line_start) &&
+ (401 == k->httpcode)) ||
+ (checkprefix("Proxy-authenticate:", line_start) &&
+ (407 == k->httpcode))) {
+ result = Curl_http_input_auth(conn, k->httpcode,
+ line_start);
+ if(result)
+ return result;
+ }
+ else if(checkprefix("Content-Length:", line_start)) {
+ cl = curlx_strtoofft(line_start +
+ strlen("Content-Length:"), NULL, 10);
+ }
+ else if(Curl_compareheader(line_start,
+ "Connection:", "close"))
+ closeConnection = TRUE;
+ else if(Curl_compareheader(line_start,
+ "Transfer-Encoding:",
+ "chunked")) {
+ infof(data, "CONNECT responded chunked\n");
+ chunked_encoding = TRUE;
+ /* init our chunky engine */
+ Curl_httpchunk_init(conn);
+ }
+ else if(Curl_compareheader(line_start,
+ "Proxy-Connection:", "close"))
+ closeConnection = TRUE;
+ else if(2 == sscanf(line_start, "HTTP/1.%d %d",
+ &subversion,
+ &k->httpcode)) {
+ /* store the HTTP code from the proxy */
+ data->info.httpproxycode = k->httpcode;
+ }
+ /* put back the letter we blanked out before */
+ line_start[perline]= letter;
+
+ perline=0; /* line starts over here */
+ line_start = ptr+1; /* this skips the zero byte we wrote */
+ }
+ }
+ }
+ break;
+ } /* switch */
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ } /* while there's buffer left and loop is requested */
+
+ if(error)
+ return CURLE_RECV_ERROR;
+
+ if(data->info.httpproxycode != 200) {
+ /* Deal with the possibly already received authenticate
+ headers. 'newurl' is set to a new URL if we must loop. */
+ result = Curl_http_auth_act(conn);
+ if(result)
+ return result;
+
+ if(conn->bits.close)
+ /* the connection has been marked for closure, most likely in the
+ Curl_http_auth_act() function and thus we can kill it at once
+ below
+ */
+ closeConnection = TRUE;
+ }
+
+ if(closeConnection && data->req.newurl) {
+ /* Connection closed by server. Don't use it anymore */
+ Curl_closesocket(conn, conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+ break;
+ }
+ } /* END NEGOTIATION PHASE */
+
+ /* If we are supposed to continue and request a new URL, which basically
+ * means the HTTP authentication is still going on so if the tunnel
+ * is complete we start over in INIT state */
+ if(data->req.newurl &&
+ (TUNNEL_COMPLETE == conn->tunnel_state[sockindex])) {
+ conn->tunnel_state[sockindex] = TUNNEL_INIT;
+ infof(data, "TUNNEL_STATE switched to: %d\n",
+ conn->tunnel_state[sockindex]);
+ }
+
+ } while(data->req.newurl);
+
+ if(200 != data->req.httpcode) {
+ failf(data, "Received HTTP code %d from proxy after CONNECT",
+ data->req.httpcode);
+
+ if(closeConnection && data->req.newurl)
+ conn->bits.proxy_connect_closed = TRUE;
+
+ if(data->req.newurl) {
+ /* this won't be used anymore for the CONNECT so free it now */
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ }
+
+ /* to back to init state */
+ conn->tunnel_state[sockindex] = TUNNEL_INIT;
+
+ return CURLE_RECV_ERROR;
+ }
+
+ conn->tunnel_state[sockindex] = TUNNEL_COMPLETE;
+
+ /* If a proxy-authorization header was used for the proxy, then we should
+ make sure that it isn't accidentally used for the document request
+ after we've connected. So let's free and clear it here. */
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ conn->allocptr.proxyuserpwd = NULL;
+
+ data->state.authproxy.done = TRUE;
+
+ infof (data, "Proxy replied OK to CONNECT request\n");
+ data->req.ignorebody = FALSE; /* put it (back) to non-ignore state */
+ conn->bits.rewindaftersend = FALSE; /* make sure this isn't set for the
+ document request */
+ return CURLE_OK;
+}
+#endif /* CURL_DISABLE_PROXY */
diff --git a/libs/libcurl/src/http_proxy.h b/libs/libcurl/src/http_proxy.h
new file mode 100644
index 0000000000..518c09383d
--- /dev/null
+++ b/libs/libcurl/src/http_proxy.h
@@ -0,0 +1,41 @@
+#ifndef HEADER_CURL_HTTP_PROXY_H
+#define HEADER_CURL_HTTP_PROXY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+#if !defined(CURL_DISABLE_PROXY) && !defined(CURL_DISABLE_HTTP)
+/* ftp can use this as well */
+CURLcode Curl_proxyCONNECT(struct connectdata *conn,
+ int tunnelsocket,
+ const char *hostname, unsigned short remote_port);
+
+/* Default proxy timeout in milliseconds */
+#define PROXY_TIMEOUT (3600*1000)
+
+CURLcode Curl_proxy_connect(struct connectdata *conn);
+
+#else
+#define Curl_proxyCONNECT(x,y,z,w) CURLE_NOT_BUILT_IN
+#define Curl_proxy_connect(x) CURLE_OK
+#endif
+
+#endif /* HEADER_CURL_HTTP_PROXY_H */
diff --git a/libs/libcurl/src/idn_win32.c b/libs/libcurl/src/idn_win32.c
new file mode 100644
index 0000000000..464964bcd0
--- /dev/null
+++ b/libs/libcurl/src/idn_win32.c
@@ -0,0 +1,85 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+ /*
+ * IDN conversions using Windows kernel32 and normaliz libraries.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_WIN32_IDN
+
+#include "curl_multibyte.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef WANT_IDN_PROTOTYPES
+WINBASEAPI int WINAPI IdnToAscii(DWORD, const WCHAR *, int, WCHAR *, int);
+WINBASEAPI int WINAPI IdnToUnicode(DWORD, const WCHAR *, int, WCHAR *, int);
+#endif
+
+#define IDN_MAX_LENGTH 255
+
+int curl_win32_idn_to_ascii(const char *in, char **out);
+int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8);
+
+int curl_win32_idn_to_ascii(const char *in, char **out)
+{
+ wchar_t *in_w = Curl_convert_UTF8_to_wchar(in);
+ if(in_w) {
+ wchar_t punycode[IDN_MAX_LENGTH];
+ if(IdnToAscii(0, in_w, -1, punycode, IDN_MAX_LENGTH) == 0) {
+ wprintf(L"ERROR %d converting to Punycode\n", GetLastError());
+ free(in_w);
+ return 0;
+ }
+ free(in_w);
+
+ *out = Curl_convert_wchar_to_UTF8(punycode);
+ if(!*out)
+ return 0;
+ }
+ return 1;
+}
+
+int curl_win32_ascii_to_idn(const char *in, size_t in_len, char **out_utf8)
+{
+ (void)in_len; /* unused */
+ if(in) {
+ WCHAR unicode[IDN_MAX_LENGTH];
+
+ if(IdnToUnicode(0, (wchar_t *)in, -1, unicode, IDN_MAX_LENGTH) == 0) {
+ wprintf(L"ERROR %d converting to Punycode\n", GetLastError());
+ return 0;
+ }
+ else {
+ *out_utf8 = Curl_convert_wchar_to_UTF8(unicode);
+ if(!*out_utf8)
+ return 0;
+ }
+ }
+ return 1;
+}
+
+#endif /* USE_WIN32_IDN */
diff --git a/libs/libcurl/src/if2ip.c b/libs/libcurl/src/if2ip.c
new file mode 100644
index 0000000000..05ae7d6f87
--- /dev/null
+++ b/libs/libcurl/src/if2ip.c
@@ -0,0 +1,218 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+# include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+#ifdef HAVE_NETDB_H
+# include <netdb.h>
+#endif
+#ifdef HAVE_SYS_SOCKIO_H
+# include <sys/sockio.h>
+#endif
+#ifdef HAVE_IFADDRS_H
+# include <ifaddrs.h>
+#endif
+#ifdef HAVE_STROPTS_H
+# include <stropts.h>
+#endif
+#ifdef __VMS
+# include <inet.h>
+#endif
+
+#include "inet_ntop.h"
+#include "strequal.h"
+#include "if2ip.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"
+
+/* ------------------------------------------------------------------ */
+
+#if defined(HAVE_GETIFADDRS)
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ bool result = FALSE;
+
+ struct ifaddrs *iface, *head;
+
+ if(getifaddrs(&head) >= 0) {
+ for(iface=head; iface != NULL; iface=iface->ifa_next) {
+ if(curl_strequal(iface->ifa_name, interf)) {
+ result = TRUE;
+ break;
+ }
+ }
+ freeifaddrs(head);
+ }
+ return result;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ const char *interf, char *buf, int buf_size)
+{
+ struct ifaddrs *iface, *head;
+ if2ip_result_t res = IF2IP_NOT_FOUND;
+
+#ifndef ENABLE_IPV6
+ (void) remote_scope;
+#endif
+
+ if(getifaddrs(&head) >= 0) {
+ for(iface=head; iface != NULL; iface=iface->ifa_next) {
+ if(iface->ifa_addr != NULL) {
+ if(iface->ifa_addr->sa_family == af) {
+ if(curl_strequal(iface->ifa_name, interf)) {
+ void *addr;
+ char *ip;
+ char scope[12]="";
+ char ipstr[64];
+#ifdef ENABLE_IPV6
+ if(af == AF_INET6) {
+ unsigned int scopeid = 0;
+ addr = &((struct sockaddr_in6 *)iface->ifa_addr)->sin6_addr;
+#ifdef HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID
+ /* Include the scope of this interface as part of the address */
+ scopeid =
+ ((struct sockaddr_in6 *)iface->ifa_addr)->sin6_scope_id;
+#endif
+ if(scopeid != remote_scope) {
+ /* We are interested only in interface addresses whose
+ scope ID matches the remote address we want to
+ connect to: global (0) for global, link-local for
+ link-local, etc... */
+ if(res == IF2IP_NOT_FOUND) res = IF2IP_AF_NOT_SUPPORTED;
+ continue;
+ }
+ if(scopeid)
+ snprintf(scope, sizeof(scope), "%%%u", scopeid);
+ }
+ else
+#endif
+ addr = &((struct sockaddr_in *)iface->ifa_addr)->sin_addr;
+ res = IF2IP_FOUND;
+ ip = (char *) Curl_inet_ntop(af, addr, ipstr, sizeof(ipstr));
+ snprintf(buf, buf_size, "%s%s", ip, scope);
+ break;
+ }
+ }
+ else if((res == IF2IP_NOT_FOUND) &&
+ curl_strequal(iface->ifa_name, interf)) {
+ res = IF2IP_AF_NOT_SUPPORTED;
+ }
+ }
+ }
+ freeifaddrs(head);
+ }
+ return res;
+}
+
+#elif defined(HAVE_IOCTL_SIOCGIFADDR)
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ /* This is here just to support the old interfaces */
+ char buf[256];
+
+ return (Curl_if2ip(AF_INET, 0, interf, buf, sizeof(buf)) ==
+ IF2IP_NOT_FOUND) ? FALSE : TRUE;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ const char *interf, char *buf, int buf_size)
+{
+ struct ifreq req;
+ struct in_addr in;
+ struct sockaddr_in *s;
+ curl_socket_t dummy;
+ size_t len;
+
+ (void)remote_scope;
+
+ if(!interf || (af != AF_INET))
+ return IF2IP_NOT_FOUND;
+
+ len = strlen(interf);
+ if(len >= sizeof(req.ifr_name))
+ return IF2IP_NOT_FOUND;
+
+ dummy = socket(AF_INET, SOCK_STREAM, 0);
+ if(CURL_SOCKET_BAD == dummy)
+ return IF2IP_NOT_FOUND;
+
+ memset(&req, 0, sizeof(req));
+ memcpy(req.ifr_name, interf, len+1);
+ req.ifr_addr.sa_family = AF_INET;
+
+ if(ioctl(dummy, SIOCGIFADDR, &req) < 0) {
+ sclose(dummy);
+ /* With SIOCGIFADDR, we cannot tell the difference between an interface
+ that does not exist and an interface that has no address of the
+ correct family. Assume the interface does not exist */
+ return IF2IP_NOT_FOUND;
+ }
+
+ s = (struct sockaddr_in *)&req.ifr_addr;
+ memcpy(&in, &s->sin_addr, sizeof(in));
+ Curl_inet_ntop(s->sin_family, &in, buf, buf_size);
+
+ sclose(dummy);
+ return IF2IP_FOUND;
+}
+
+#else
+
+bool Curl_if_is_interface_name(const char *interf)
+{
+ (void) interf;
+
+ return FALSE;
+}
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ const char *interf, char *buf, int buf_size)
+{
+ (void) af;
+ (void) remote_scope;
+ (void) interf;
+ (void) buf;
+ (void) buf_size;
+ return IF2IP_NOT_FOUND;
+}
+
+#endif
diff --git a/libs/libcurl/src/if2ip.h b/libs/libcurl/src/if2ip.h
new file mode 100644
index 0000000000..ac58752378
--- /dev/null
+++ b/libs/libcurl/src/if2ip.h
@@ -0,0 +1,74 @@
+#ifndef HEADER_CURL_IF2IP_H
+#define HEADER_CURL_IF2IP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+bool Curl_if_is_interface_name(const char *interf);
+
+typedef enum {
+ IF2IP_NOT_FOUND = 0, /* Interface not found */
+ IF2IP_AF_NOT_SUPPORTED = 1, /* Int. exists but has no address for this af */
+ IF2IP_FOUND = 2 /* The address has been stored in "buf" */
+} if2ip_result_t;
+
+if2ip_result_t Curl_if2ip(int af, unsigned int remote_scope,
+ const char *interf, char *buf, int buf_size);
+
+#ifdef __INTERIX
+
+/* Nedelcho Stanev's work-around for SFU 3.0 */
+struct ifreq {
+#define IFNAMSIZ 16
+#define IFHWADDRLEN 6
+ union {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ } ifr_ifrn;
+
+ union {
+ struct sockaddr ifru_addr;
+ struct sockaddr ifru_broadaddr;
+ struct sockaddr ifru_netmask;
+ struct sockaddr ifru_hwaddr;
+ short ifru_flags;
+ int ifru_metric;
+ int ifru_mtu;
+ } ifr_ifru;
+};
+
+/* This define was added by Daniel to avoid an extra #ifdef INTERIX in the
+ C code. */
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_addr ifr_ifru.ifru_addr /* address */
+#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
+#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */
+#define ifr_flags ifr_ifru.ifru_flags /* flags */
+#define ifr_hwaddr ifr_ifru.ifru_hwaddr /* MAC address */
+#define ifr_metric ifr_ifru.ifru_metric /* metric */
+#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */
+
+#define SIOCGIFADDR _IOW('s', 102, struct ifreq) /* Get if addr */
+
+#endif /* __INTERIX */
+
+#endif /* HEADER_CURL_IF2IP_H */
diff --git a/libs/libcurl/src/imap.c b/libs/libcurl/src/imap.c
new file mode 100644
index 0000000000..9a845102ad
--- /dev/null
+++ b/libs/libcurl/src/imap.c
@@ -0,0 +1,2452 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3501 IMAPv4 protocol
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4959 IMAP Extension for SASL Initial Client Response
+ * RFC5092 IMAP URL Scheme
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_IMAP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "imap.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "curl_sasl.h"
+#include "warnless.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"
+
+/* Local API functions */
+static CURLcode imap_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode imap_do(struct connectdata *conn, bool *done);
+static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode imap_connect(struct connectdata *conn, bool *done);
+static CURLcode imap_disconnect(struct connectdata *conn, bool dead);
+static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done);
+static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode imap_setup_connection(struct connectdata *conn);
+static char *imap_atom(const char *str);
+static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...);
+static CURLcode imap_parse_url_options(struct connectdata *conn);
+static CURLcode imap_parse_url_path(struct connectdata *conn);
+static CURLcode imap_parse_custom_request(struct connectdata *conn);
+
+/*
+ * IMAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imap = {
+ "IMAP", /* scheme */
+ imap_setup_connection, /* setup_connection */
+ imap_do, /* do_it */
+ imap_done, /* done */
+ ZERO_NULL, /* do_more */
+ imap_connect, /* connect_it */
+ imap_multi_statemach, /* connecting */
+ imap_doing, /* doing */
+ imap_getsock, /* proto_getsock */
+ imap_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ imap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAP, /* defport */
+ CURLPROTO_IMAP, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_NEEDSPWD
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * IMAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_imaps = {
+ "IMAPS", /* scheme */
+ imap_setup_connection, /* setup_connection */
+ imap_do, /* do_it */
+ imap_done, /* done */
+ ZERO_NULL, /* do_more */
+ imap_connect, /* connect_it */
+ imap_multi_statemach, /* connecting */
+ imap_doing, /* doing */
+ imap_getsock, /* proto_getsock */
+ imap_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ imap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAPS, /* defport */
+ CURLPROTO_IMAP | CURLPROTO_IMAPS, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL | PROTOPT_NEEDSPWD
+ | PROTOPT_NOURLQUERY /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed IMAP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imap_proxy = {
+ "IMAP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed IMAPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_imaps_proxy = {
+ "IMAPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_IMAPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+#ifdef USE_SSL
+static void imap_to_imaps(struct connectdata *conn)
+{
+ conn->handler = &Curl_handler_imaps;
+}
+#else
+#define imap_to_imaps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * imap_matchresp()
+ *
+ * Determines whether the untagged response is related to the specified
+ * command by checking if it is in format "* <command-name> ..." or
+ * "* <number> <command-name> ...".
+ *
+ * The "* " marker is assumed to have already been checked by the caller.
+ */
+static bool imap_matchresp(const char *line, size_t len, const char *cmd)
+{
+ const char *end = line + len;
+ size_t cmd_len = strlen(cmd);
+
+ /* Skip the untagged response marker */
+ line += 2;
+
+ /* Do we have a number after the marker? */
+ if(line < end && ISDIGIT(*line)) {
+ /* Skip the number */
+ do
+ line++;
+ while(line < end && ISDIGIT(*line));
+
+ /* Do we have the space character? */
+ if(line == end || *line != ' ')
+ return FALSE;
+
+ line++;
+ }
+
+ /* Does the command name match and is it followed by a space character or at
+ the end of line? */
+ if(line + cmd_len <= end && Curl_raw_nequal(line, cmd, cmd_len) &&
+ (line[cmd_len] == ' ' || line + cmd_len == end))
+ return TRUE;
+
+ return FALSE;
+}
+
+/***********************************************************************
+ *
+ * imap_endofresp()
+ *
+ * Checks whether the given string is a valid tagged, untagged or continuation
+ * response which can be processed by the response handler.
+ */
+static bool imap_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct IMAP *imap = conn->data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *id = imapc->resptag;
+ size_t id_len = strlen(id);
+
+ /* Do we have a tagged command response? */
+ if(len >= id_len + 1 && !memcmp(id, line, id_len) && line[id_len] == ' ') {
+ line += id_len + 1;
+ len -= id_len + 1;
+
+ if(len >= 2 && !memcmp(line, "OK", 2))
+ *resp = 'O';
+ else if(len >= 2 && !memcmp(line, "NO", 2))
+ *resp = 'N';
+ else if(len >= 3 && !memcmp(line, "BAD", 3))
+ *resp = 'B';
+ else {
+ failf(conn->data, "Bad tagged response");
+ *resp = -1;
+ }
+
+ return TRUE;
+ }
+
+ /* Do we have an untagged command response? */
+ if(len >= 2 && !memcmp("* ", line, 2)) {
+ switch(imapc->state) {
+ /* States which are interested in untagged responses */
+ case IMAP_CAPABILITY:
+ if(!imap_matchresp(line, len, "CAPABILITY"))
+ return FALSE;
+ break;
+
+ case IMAP_LIST:
+ if((!imap->custom && !imap_matchresp(line, len, "LIST")) ||
+ (imap->custom && !imap_matchresp(line, len, imap->custom) &&
+ (strcmp(imap->custom, "STORE") ||
+ !imap_matchresp(line, len, "FETCH")) &&
+ strcmp(imap->custom, "SELECT") &&
+ strcmp(imap->custom, "EXAMINE") &&
+ strcmp(imap->custom, "SEARCH") &&
+ strcmp(imap->custom, "EXPUNGE") &&
+ strcmp(imap->custom, "LSUB") &&
+ strcmp(imap->custom, "UID") &&
+ strcmp(imap->custom, "NOOP")))
+ return FALSE;
+ break;
+
+ case IMAP_SELECT:
+ /* SELECT is special in that its untagged responses do not have a
+ common prefix so accept anything! */
+ break;
+
+ case IMAP_FETCH:
+ if(!imap_matchresp(line, len, "FETCH"))
+ return FALSE;
+ break;
+
+ /* Ignore other untagged responses */
+ default:
+ return FALSE;
+ }
+
+ *resp = '*';
+ return TRUE;
+ }
+
+ /* Do we have a continuation response? This should be a + symbol followed by
+ a space and optionally some text as per RFC-3501 for the AUTHENTICATE and
+ APPEND commands and as outlined in Section 4. Examples of RFC-4959 but
+ some e-mail servers ignore this and only send a single + instead. */
+ if((len == 3 && !memcmp("+", line, 1)) ||
+ (len >= 2 && !memcmp("+ ", line, 2))) {
+ switch(imapc->state) {
+ /* States which are interested in continuation responses */
+ case IMAP_AUTHENTICATE_PLAIN:
+ case IMAP_AUTHENTICATE_LOGIN:
+ case IMAP_AUTHENTICATE_LOGIN_PASSWD:
+ case IMAP_AUTHENTICATE_CRAMMD5:
+ case IMAP_AUTHENTICATE_DIGESTMD5:
+ case IMAP_AUTHENTICATE_DIGESTMD5_RESP:
+ case IMAP_AUTHENTICATE_NTLM:
+ case IMAP_AUTHENTICATE_NTLM_TYPE2MSG:
+ case IMAP_AUTHENTICATE_XOAUTH2:
+ case IMAP_AUTHENTICATE_FINAL:
+ case IMAP_APPEND:
+ *resp = '+';
+ break;
+
+ default:
+ failf(conn->data, "Unexpected continuation response");
+ *resp = -1;
+ break;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change IMAP state!
+ */
+static void state(struct connectdata *conn, imapstate newstate)
+{
+ struct imap_conn *imapc = &conn->proto.imapc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[]={
+ "STOP",
+ "SERVERGREET",
+ "CAPABILITY",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTHENTICATE_PLAIN",
+ "AUTHENTICATE_LOGIN",
+ "AUTHENTICATE_LOGIN_PASSWD",
+ "AUTHENTICATE_CRAMMD5",
+ "AUTHENTICATE_DIGESTMD5",
+ "AUTHENTICATE_DIGESTMD5_RESP",
+ "AUTHENTICATE_NTLM",
+ "AUTHENTICATE_NTLM_TYPE2MSG",
+ "AUTHENTICATE_XOAUTH2",
+ "AUTHENTICATE_FINAL",
+ "LOGIN",
+ "LIST",
+ "SELECT",
+ "FETCH",
+ "FETCH_FINAL",
+ "APPEND",
+ "APPEND_FINAL",
+ "LOGOUT",
+ /* LAST */
+ };
+
+ if(imapc->state != newstate)
+ infof(conn->data, "IMAP %p state change from %s to %s\n",
+ (void *)imapc, names[imapc->state], names[newstate]);
+#endif
+
+ imapc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_capability()
+ *
+ * Sends the CAPABILITY command in order to obtain a list of server side
+ * supported capabilities.
+ */
+static CURLcode imap_perform_capability(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ imapc->authmechs = 0; /* No known authentication mechanisms yet */
+ imapc->authused = 0; /* Clear the authentication mechanism used */
+ imapc->tls_supported = FALSE; /* Clear the TLS capability */
+
+ /* Send the CAPABILITY command */
+ result = imap_sendf(conn, "CAPABILITY");
+
+ if(!result)
+ state(conn, IMAP_CAPABILITY);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_starttls()
+ *
+ * Sends the STARTTLS command to start the upgrade to TLS.
+ */
+static CURLcode imap_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STARTTLS command */
+ result = imap_sendf(conn, "STARTTLS");
+
+ if(!result)
+ state(conn, IMAP_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode imap_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
+
+ if(!result) {
+ if(imapc->state != IMAP_UPGRADETLS)
+ state(conn, IMAP_UPGRADETLS);
+
+ if(imapc->ssldone) {
+ imap_to_imaps(conn);
+ result = imap_perform_capability(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_login()
+ *
+ * Sends a clear text LOGIN command to authenticate with.
+ */
+static CURLcode imap_perform_login(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ char *user;
+ char *passwd;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, IMAP_STOP);
+
+ return result;
+ }
+
+ /* Make sure the username and password are in the correct atom format */
+ user = imap_atom(conn->user);
+ passwd = imap_atom(conn->passwd);
+
+ /* Send the LOGIN command */
+ result = imap_sendf(conn, "LOGIN %s %s", user ? user : "",
+ passwd ? passwd : "");
+
+ Curl_safefree(user);
+ Curl_safefree(passwd);
+
+ if(!result)
+ state(conn, IMAP_LOGIN);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_authenticate()
+ *
+ * Sends an AUTHENTICATE command allowing the client to login with the
+ * appropriate SASL authentication mechanism.
+ *
+ * Additionally, the function will perform fallback to the LOGIN command
+ * should a common mechanism not be available between the client and server.
+ */
+static CURLcode imap_perform_authenticate(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *mech = NULL;
+ char *initresp = NULL;
+ size_t len = 0;
+ imapstate state1 = IMAP_STOP;
+ imapstate state2 = IMAP_STOP;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, IMAP_STOP);
+
+ return result;
+ }
+
+ /* Calculate the supported authentication mechanism by decreasing order of
+ security */
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if((imapc->authmechs & SASL_MECH_DIGEST_MD5) &&
+ (imapc->prefmech & SASL_MECH_DIGEST_MD5)) {
+ mech = SASL_MECH_STRING_DIGEST_MD5;
+ state1 = IMAP_AUTHENTICATE_DIGESTMD5;
+ imapc->authused = SASL_MECH_DIGEST_MD5;
+ }
+ else if((imapc->authmechs & SASL_MECH_CRAM_MD5) &&
+ (imapc->prefmech & SASL_MECH_CRAM_MD5)) {
+ mech = SASL_MECH_STRING_CRAM_MD5;
+ state1 = IMAP_AUTHENTICATE_CRAMMD5;
+ imapc->authused = SASL_MECH_CRAM_MD5;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if((imapc->authmechs & SASL_MECH_NTLM) &&
+ (imapc->prefmech & SASL_MECH_NTLM)) {
+ mech = SASL_MECH_STRING_NTLM;
+ state1 = IMAP_AUTHENTICATE_NTLM;
+ state2 = IMAP_AUTHENTICATE_NTLM_TYPE2MSG;
+ imapc->authused = SASL_MECH_NTLM;
+
+ if(imapc->ir_supported || data->set.sasl_ir)
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &initresp, &len);
+ }
+ else
+#endif
+ if(((imapc->authmechs & SASL_MECH_XOAUTH2) &&
+ (imapc->prefmech & SASL_MECH_XOAUTH2) &&
+ (imapc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
+ mech = SASL_MECH_STRING_XOAUTH2;
+ state1 = IMAP_AUTHENTICATE_XOAUTH2;
+ state2 = IMAP_AUTHENTICATE_FINAL;
+ imapc->authused = SASL_MECH_XOAUTH2;
+
+ if(imapc->ir_supported || data->set.sasl_ir)
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &initresp, &len);
+ }
+ else if((imapc->authmechs & SASL_MECH_LOGIN) &&
+ (imapc->prefmech & SASL_MECH_LOGIN)) {
+ mech = SASL_MECH_STRING_LOGIN;
+ state1 = IMAP_AUTHENTICATE_LOGIN;
+ state2 = IMAP_AUTHENTICATE_LOGIN_PASSWD;
+ imapc->authused = SASL_MECH_LOGIN;
+
+ if(imapc->ir_supported || data->set.sasl_ir)
+ result = Curl_sasl_create_login_message(conn->data, conn->user,
+ &initresp, &len);
+ }
+ else if((imapc->authmechs & SASL_MECH_PLAIN) &&
+ (imapc->prefmech & SASL_MECH_PLAIN)) {
+ mech = SASL_MECH_STRING_PLAIN;
+ state1 = IMAP_AUTHENTICATE_PLAIN;
+ state2 = IMAP_AUTHENTICATE_FINAL;
+ imapc->authused = SASL_MECH_PLAIN;
+
+ if(imapc->ir_supported || data->set.sasl_ir)
+ result = Curl_sasl_create_plain_message(conn->data, conn->user,
+ conn->passwd, &initresp, &len);
+ }
+
+ if(!result) {
+ if(mech) {
+ /* Perform SASL based authentication */
+ if(initresp) {
+ result = imap_sendf(conn, "AUTHENTICATE %s %s", mech, initresp);
+
+ if(!result)
+ state(conn, state2);
+ }
+ else {
+ result = imap_sendf(conn, "AUTHENTICATE %s", mech);
+
+ if(!result)
+ state(conn, state1);
+ }
+
+ Curl_safefree(initresp);
+ }
+ else if(!imapc->login_disabled)
+ /* Perform clear text authentication */
+ result = imap_perform_login(conn);
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_list()
+ *
+ * Sends a LIST command or an alternative custom request.
+ */
+static CURLcode imap_perform_list(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ char *mailbox;
+
+ if(imap->custom)
+ /* Send the custom request */
+ result = imap_sendf(conn, "%s%s", imap->custom,
+ imap->custom_params ? imap->custom_params : "");
+ else {
+ /* Make sure the mailbox is in the correct atom format */
+ mailbox = imap_atom(imap->mailbox ? imap->mailbox : "");
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the LIST command */
+ result = imap_sendf(conn, "LIST \"%s\" *", mailbox);
+
+ Curl_safefree(mailbox);
+ }
+
+ if(!result)
+ state(conn, IMAP_LIST);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_select()
+ *
+ * Sends a SELECT command to ask the server to change the selected mailbox.
+ */
+static CURLcode imap_perform_select(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ char *mailbox;
+
+ /* Invalidate old information as we are switching mailboxes */
+ Curl_safefree(imapc->mailbox);
+ Curl_safefree(imapc->mailbox_uidvalidity);
+
+ /* Check we have a mailbox */
+ if(!imap->mailbox) {
+ failf(conn->data, "Cannot SELECT without a mailbox.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Make sure the mailbox is in the correct atom format */
+ mailbox = imap_atom(imap->mailbox);
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the SELECT command */
+ result = imap_sendf(conn, "SELECT %s", mailbox);
+
+ Curl_safefree(mailbox);
+
+ if(!result)
+ state(conn, IMAP_SELECT);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_fetch()
+ *
+ * Sends a FETCH command to initiate the download of a message.
+ */
+static CURLcode imap_perform_fetch(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct IMAP *imap = conn->data->req.protop;
+
+ /* Check we have a UID */
+ if(!imap->uid) {
+ failf(conn->data, "Cannot FETCH without a UID.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Send the FETCH command */
+ result = imap_sendf(conn, "FETCH %s BODY[%s]",
+ imap->uid,
+ imap->section ? imap->section : "");
+
+ if(!result)
+ state(conn, IMAP_FETCH);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_append()
+ *
+ * Sends an APPEND command to initiate the upload of a message.
+ */
+static CURLcode imap_perform_append(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct IMAP *imap = conn->data->req.protop;
+ char *mailbox;
+
+ /* Check we have a mailbox */
+ if(!imap->mailbox) {
+ failf(conn->data, "Cannot APPEND without a mailbox.");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Check we know the size of the upload */
+ if(conn->data->set.infilesize < 0) {
+ failf(conn->data, "Cannot APPEND with unknown input file size\n");
+ return CURLE_UPLOAD_FAILED;
+ }
+
+ /* Make sure the mailbox is in the correct atom format */
+ mailbox = imap_atom(imap->mailbox);
+ if(!mailbox)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the APPEND command */
+ result = imap_sendf(conn, "APPEND %s (\\Seen) {%" FORMAT_OFF_T "}",
+ mailbox, conn->data->set.infilesize);
+
+ Curl_safefree(mailbox);
+
+ if(!result)
+ state(conn, IMAP_APPEND);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform_logout()
+ *
+ * Performs the logout action prior to sclose() being called.
+ */
+static CURLcode imap_perform_logout(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the LOGOUT command */
+ result = imap_sendf(conn, "LOGOUT");
+
+ if(!result)
+ state(conn, IMAP_LOGOUT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode imap_state_servergreet_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Got unexpected imap-server response");
+ result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
+ }
+ else
+ result = imap_perform_capability(conn);
+
+ return result;
+}
+
+/* For CAPABILITY responses */
+static CURLcode imap_state_capability_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *line = data->state.buffer;
+ size_t wordlen;
+
+ (void)instate; /* no use for this yet */
+
+ /* Do we have a untagged response? */
+ if(imapcode == '*') {
+ line += 2;
+
+ /* Loop through the data line */
+ for(;;) {
+ while(*line &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ }
+
+ if(!*line)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; line[wordlen] && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Does the server support the STARTTLS capability? */
+ if(wordlen == 8 && !memcmp(line, "STARTTLS", 8))
+ imapc->tls_supported = TRUE;
+
+ /* Has the server explicitly disabled clear text authentication? */
+ else if(wordlen == 13 && !memcmp(line, "LOGINDISABLED", 13))
+ imapc->login_disabled = TRUE;
+
+ /* Does the server support the SASL-IR capability? */
+ else if(wordlen == 7 && !memcmp(line, "SASL-IR", 7))
+ imapc->ir_supported = TRUE;
+
+ /* Do we have a SASL based authentication mechanism? */
+ else if(wordlen > 5 && !memcmp(line, "AUTH=", 5)) {
+ line += 5;
+ wordlen -= 5;
+
+ /* Test the word for a matching authentication mechanism */
+ if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
+ imapc->authmechs |= SASL_MECH_LOGIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
+ imapc->authmechs |= SASL_MECH_PLAIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
+ imapc->authmechs |= SASL_MECH_CRAM_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
+ imapc->authmechs |= SASL_MECH_DIGEST_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
+ imapc->authmechs |= SASL_MECH_GSSAPI;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
+ imapc->authmechs |= SASL_MECH_EXTERNAL;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
+ imapc->authmechs |= SASL_MECH_NTLM;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
+ imapc->authmechs |= SASL_MECH_XOAUTH2;
+ }
+
+ line += wordlen;
+ }
+ }
+ else if(imapcode == 'O') {
+ if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(imapc->tls_supported)
+ /* Switch to TLS connection now */
+ result = imap_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = imap_perform_authenticate(conn);
+ else {
+ failf(data, "STARTTLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = imap_perform_authenticate(conn);
+ }
+ else
+ result = imap_perform_login(conn);
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode imap_state_starttls_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied. %c", imapcode);
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = imap_perform_authenticate(conn);
+ }
+ else
+ result = imap_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For AUTHENTICATE PLAIN (without initial response) responses */
+static CURLcode imap_state_auth_plain_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *plainauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied. %c", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
+ &plainauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(plainauth) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", plainauth);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ Curl_safefree(plainauth);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTHENTICATE LOGIN (without initial response) responses */
+static CURLcode imap_state_auth_login_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authuser = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the user message */
+ result = Curl_sasl_create_login_message(data, conn->user,
+ &authuser, &len);
+
+ /* Send the user */
+ if(!result) {
+ if(authuser) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authuser);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_LOGIN_PASSWD);
+ }
+
+ Curl_safefree(authuser);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTHENTICATE LOGIN user entry responses */
+static CURLcode imap_state_auth_login_password_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authpasswd = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the password message */
+ result = Curl_sasl_create_login_message(data, conn->passwd,
+ &authpasswd, &len);
+
+ /* Send the password */
+ if(!result) {
+ if(authpasswd) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", authpasswd);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ Curl_safefree(authpasswd);
+ }
+ }
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* For AUTHENTICATE CRAM-MD5 responses */
+static CURLcode imap_state_auth_cram_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Terminate the challenge */
+ if(*chlg64 != '=') {
+ for(len = strlen(chlg64); len--;)
+ if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
+ chlg64[len] != '\t')
+ break;
+
+ if(++len) {
+ chlg64[len] = '\0';
+ }
+ }
+
+ /* Create the response message */
+ result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
+ conn->passwd, &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTHENTICATE DIGEST-MD5 challenge responses */
+static CURLcode imap_state_auth_digest_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Create the response message */
+ result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
+ conn->passwd, "imap",
+ &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_DIGESTMD5_RESP);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTHENTICATE DIGEST-MD5 challenge-response responses */
+static CURLcode imap_state_auth_digest_resp_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Authentication failed: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Send an empty response */
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ return result;
+}
+#endif
+
+#ifdef USE_NTLM
+/* For AUTHENTICATE NTLM (without initial response) responses */
+static CURLcode imap_state_auth_ntlm_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *type1msg = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-1 message */
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &type1msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type1msg) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type1msg);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_NTLM_TYPE2MSG);
+ }
+
+ Curl_safefree(type1msg);
+ }
+ }
+
+ return result;
+}
+
+/* For NTLM type-2 responses (sent in reponse to our type-1 message) */
+static CURLcode imap_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *type3msg = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-3 message */
+ result = Curl_sasl_create_ntlm_type3_message(data,
+ data->state.buffer + 2,
+ conn->user, conn->passwd,
+ &conn->ntlm,
+ &type3msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type3msg) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", type3msg);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ Curl_safefree(type3msg);
+ }
+ }
+
+ return result;
+}
+#endif
+
+/* For AUTH XOAUTH2 (without initial response) responses */
+static CURLcode imap_state_auth_xoauth2_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *xoauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '+') {
+ failf(data, "Access denied: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &xoauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(xoauth) {
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", xoauth);
+
+ if(!result)
+ state(conn, IMAP_AUTHENTICATE_FINAL);
+ }
+
+ Curl_safefree(xoauth);
+ }
+ }
+
+ return result;
+}
+
+/* For final responses to the AUTHENTICATE sequence */
+static CURLcode imap_state_auth_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Authentication failed: %d", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For LOGIN responses */
+static CURLcode imap_state_login_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != 'O') {
+ failf(data, "Access denied. %c", imapcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For LIST responses */
+static CURLcode imap_state_list_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ char *line = conn->data->state.buffer;
+ size_t len = strlen(line);
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode == '*') {
+ /* Temporarily add the LF character back and send as body to the client */
+ line[len] = '\n';
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, line, len + 1);
+ line[len] = '\0';
+ }
+ else if(imapcode != 'O')
+ result = CURLE_QUOTE_ERROR; /* TODO: Fix error code */
+ else
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For SELECT responses */
+static CURLcode imap_state_select_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = conn->data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *line = data->state.buffer;
+ char tmp[20];
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode == '*') {
+ /* See if this is an UIDVALIDITY response */
+ if(sscanf(line + 2, "OK [UIDVALIDITY %19[0123456789]]", tmp) == 1) {
+ Curl_safefree(imapc->mailbox_uidvalidity);
+ imapc->mailbox_uidvalidity = strdup(tmp);
+ }
+ }
+ else if(imapcode == 'O') {
+ /* Check if the UIDVALIDITY has been specified and matches */
+ if(imap->uidvalidity && imapc->mailbox_uidvalidity &&
+ strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)) {
+ failf(conn->data, "Mailbox UIDVALIDITY has changed");
+ result = CURLE_REMOTE_FILE_NOT_FOUND;
+ }
+ else {
+ /* Note the currently opened mailbox on this connection */
+ imapc->mailbox = strdup(imap->mailbox);
+
+ if(imap->custom)
+ result = imap_perform_list(conn);
+ else
+ result = imap_perform_fetch(conn);
+ }
+ }
+ else {
+ failf(data, "Select failed");
+ result = CURLE_LOGIN_DENIED;
+ }
+
+ return result;
+}
+
+/* For the (first line of the) FETCH responses */
+static CURLcode imap_state_fetch_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+ const char *ptr = data->state.buffer;
+ bool parsed = FALSE;
+ curl_off_t size;
+
+ (void)instate; /* no use for this yet */
+
+ if(imapcode != '*') {
+ Curl_pgrsSetDownloadSize(data, 0);
+ state(conn, IMAP_STOP);
+ return CURLE_REMOTE_FILE_NOT_FOUND; /* TODO: Fix error code */
+ }
+
+ /* Something like this is received "* 1 FETCH (BODY[TEXT] {2021}\r" so parse
+ the continuation data contained within the curly brackets */
+ while(*ptr && (*ptr != '{'))
+ ptr++;
+
+ if(*ptr == '{') {
+ char *endptr;
+ size = curlx_strtoofft(ptr + 1, &endptr, 10);
+ if(endptr - ptr > 1 && endptr[0] == '}' &&
+ endptr[1] == '\r' && endptr[2] == '\0')
+ parsed = TRUE;
+ }
+
+ if(parsed) {
+ infof(data, "Found %" FORMAT_OFF_TU " bytes to download\n", size);
+ Curl_pgrsSetDownloadSize(data, size);
+
+ if(pp->cache) {
+ /* At this point there is a bunch of data in the header "cache" that is
+ actually body content, send it as body and then skip it. Do note
+ that there may even be additional "headers" after the body. */
+ size_t chunk = pp->cache_size;
+
+ if(chunk > (size_t)size)
+ /* The conversion from curl_off_t to size_t is always fine here */
+ chunk = (size_t)size;
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, pp->cache, chunk);
+ if(result)
+ return result;
+
+ data->req.bytecount += chunk;
+
+ infof(data, "Written %" FORMAT_OFF_TU " bytes, %" FORMAT_OFF_TU
+ " bytes are left for transfer\n", (curl_off_t)chunk,
+ size - chunk);
+
+ /* Have we used the entire cache or just part of it?*/
+ if(pp->cache_size > chunk) {
+ /* Only part of it so shrink the cache to fit the trailing data */
+ memmove(pp->cache, pp->cache + chunk, pp->cache_size - chunk);
+ pp->cache_size -= chunk;
+ }
+ else {
+ /* Free the cache */
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
+ }
+ }
+
+ if(data->req.bytecount == size)
+ /* The entire data is already transferred! */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ else {
+ /* IMAP download */
+ data->req.maxdownload = size;
+ Curl_setup_transfer(conn, FIRSTSOCKET, size, FALSE, NULL, -1, NULL);
+ }
+ }
+ else {
+ /* We don't know how to parse this line */
+ failf(pp->conn->data, "Failed to parse FETCH response.");
+ result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: fix this code */
+ }
+
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For final FETCH responses performed after the download */
+static CURLcode imap_state_fetch_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != 'O')
+ result = CURLE_FTP_WEIRD_SERVER_REPLY; /* TODO: Fix error code */
+ else
+ /* End of DONE phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+/* For APPEND responses */
+static CURLcode imap_state_append_resp(struct connectdata *conn, int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != '+') {
+ result = CURLE_UPLOAD_FAILED;
+ }
+ else {
+ /* Set the progress upload size */
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+ /* IMAP upload */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* End of DO phase */
+ state(conn, IMAP_STOP);
+ }
+
+ return result;
+}
+
+/* For final APPEND responses performed after the upload */
+static CURLcode imap_state_append_final_resp(struct connectdata *conn,
+ int imapcode,
+ imapstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* No use for this yet */
+
+ if(imapcode != 'O')
+ result = CURLE_UPLOAD_FAILED;
+ else
+ /* End of DONE phase */
+ state(conn, IMAP_STOP);
+
+ return result;
+}
+
+static CURLcode imap_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int imapcode;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not IMAP */
+ if(imapc->state == IMAP_UPGRADETLS)
+ return imap_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ do {
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &imapcode, &nread);
+ if(result)
+ return result;
+
+ /* Was there an error parsing the response line? */
+ if(imapcode == -1)
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+
+ if(!imapcode)
+ break;
+
+ /* We have now received a full IMAP server response */
+ switch(imapc->state) {
+ case IMAP_SERVERGREET:
+ result = imap_state_servergreet_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_CAPABILITY:
+ result = imap_state_capability_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_STARTTLS:
+ result = imap_state_starttls_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_PLAIN:
+ result = imap_state_auth_plain_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_LOGIN:
+ result = imap_state_auth_login_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_LOGIN_PASSWD:
+ result = imap_state_auth_login_password_resp(conn, imapcode,
+ imapc->state);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case IMAP_AUTHENTICATE_CRAMMD5:
+ result = imap_state_auth_cram_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_DIGESTMD5:
+ result = imap_state_auth_digest_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_DIGESTMD5_RESP:
+ result = imap_state_auth_digest_resp_resp(conn, imapcode, imapc->state);
+ break;
+#endif
+
+#ifdef USE_NTLM
+ case IMAP_AUTHENTICATE_NTLM:
+ result = imap_state_auth_ntlm_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_NTLM_TYPE2MSG:
+ result = imap_state_auth_ntlm_type2msg_resp(conn, imapcode,
+ imapc->state);
+ break;
+#endif
+
+ case IMAP_AUTHENTICATE_XOAUTH2:
+ result = imap_state_auth_xoauth2_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_AUTHENTICATE_FINAL:
+ result = imap_state_auth_final_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LOGIN:
+ result = imap_state_login_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LIST:
+ result = imap_state_list_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_SELECT:
+ result = imap_state_select_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_FETCH:
+ result = imap_state_fetch_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_FETCH_FINAL:
+ result = imap_state_fetch_final_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_APPEND:
+ result = imap_state_append_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_APPEND_FINAL:
+ result = imap_state_append_final_resp(conn, imapcode, imapc->state);
+ break;
+
+ case IMAP_LOGOUT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, IMAP_STOP);
+ break;
+ }
+ } while(!result && imapc->state != IMAP_STOP && Curl_pp_moredata(pp));
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode imap_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !imapc->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &imapc->ssldone);
+ if(result || !imapc->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&imapc->pp, FALSE);
+ *done = (imapc->state == IMAP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode imap_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ while(imapc->state != IMAP_STOP && !result)
+ result = Curl_pp_statemach(&imapc->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the struct IMAP for the current SessionHandle if
+ required */
+static CURLcode imap_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap;
+
+ imap = data->req.protop = calloc(sizeof(struct IMAP), 1);
+ if(!imap)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the IMAP "protocol connect" and "doing" phases only */
+static int imap_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.imapc.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * imap_connect()
+ *
+ * This function 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 if not.
+ */
+static CURLcode imap_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ struct pingpong *pp = &imapc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in IMAP */
+ conn->bits.close = FALSE;
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = imap_statemach_act;
+ pp->endofresp = imap_endofresp;
+ pp->conn = conn;
+
+ /* Set the default preferred authentication mechanism */
+ imapc->prefmech = SASL_AUTH_ANY;
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = imap_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, IMAP_SERVERGREET);
+
+ /* Start off with an response id of '*' */
+ strcpy(imapc->resptag, "*");
+
+ result = imap_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode imap_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+
+ (void)premature;
+
+ if(!imap)
+ /* When the easy handle is removed from the multi interface while libcurl
+ is still trying to resolve the host name, the IMAP struct is not yet
+ initialized. However, the removal action calls Curl_done() which in
+ turn calls this function, so we simply return success. */
+ return CURLE_OK;
+
+ if(status) {
+ conn->bits.close = TRUE; /* marked for closure */
+ result = status; /* use the already set error code */
+ }
+ else if(!data->set.connect_only && !imap->custom &&
+ (imap->uid || data->set.upload)) {
+ /* Handle responses after FETCH or APPEND transfer has finished */
+ if(!data->set.upload)
+ state(conn, IMAP_FETCH_FINAL);
+ else {
+ /* End the APPEND command first by sending an empty line */
+ result = Curl_pp_sendf(&conn->proto.imapc.pp, "%s", "");
+ if(!result)
+ state(conn, IMAP_APPEND_FINAL);
+ }
+
+ /* Run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the imap_multi_statemach function but we have no general support for
+ non-blocking DONE operations, not in the multi state machine and with
+ Curl_done() invokes on several places in the code!
+ */
+ if(!result)
+ result = imap_block_statemach(conn);
+ }
+
+ /* Cleanup our per-request based variables */
+ Curl_safefree(imap->mailbox);
+ Curl_safefree(imap->uidvalidity);
+ Curl_safefree(imap->uid);
+ Curl_safefree(imap->section);
+ Curl_safefree(imap->custom);
+ Curl_safefree(imap->custom_params);
+
+ /* Clear the transfer mode for the next request */
+ imap->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_perform()
+ *
+ * This is the actual DO function for IMAP. Fetch or append a message, or do
+ * other things according to the options previously setup.
+ */
+static CURLcode imap_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is IMAP and no proxy */
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ bool selected = FALSE;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ imap->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Determine if the requested mailbox (with the same UIDVALIDITY if set)
+ has already been selected on this connection */
+ if(imap->mailbox && imapc->mailbox &&
+ !strcmp(imap->mailbox, imapc->mailbox) &&
+ (!imap->uidvalidity || !imapc->mailbox_uidvalidity ||
+ !strcmp(imap->uidvalidity, imapc->mailbox_uidvalidity)))
+ selected = TRUE;
+
+ /* Start the first command in the DO phase */
+ if(conn->data->set.upload)
+ /* APPEND can be executed directly */
+ result = imap_perform_append(conn);
+ else if(imap->custom && (selected || !imap->mailbox))
+ /* Custom command using the same mailbox or no mailbox */
+ result = imap_perform_list(conn);
+ else if(!imap->custom && selected && imap->uid)
+ /* FETCH from the same mailbox */
+ result = imap_perform_fetch(conn);
+ else if(imap->mailbox && !selected && (imap->custom || imap->uid))
+ /* SELECT the mailbox */
+ result = imap_perform_select(conn);
+ else
+ /* LIST */
+ result = imap_perform_list(conn);
+
+ if(result)
+ return result;
+
+ /* Run the state-machine */
+ result = imap_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (imap_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode imap_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ /* Parse the URL path */
+ result = imap_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Parse the custom request */
+ result = imap_parse_custom_request(conn);
+ if(result)
+ return result;
+
+ result = imap_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_disconnect()
+ *
+ * Disconnect from an IMAP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode imap_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct imap_conn *imapc = &conn->proto.imapc;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The IMAP session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && imapc->pp.conn)
+ if(!imap_perform_logout(conn))
+ (void)imap_block_statemach(conn); /* ignore errors on LOGOUT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&imapc->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, imapc->authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(imapc->mailbox);
+ Curl_safefree(imapc->mailbox_uidvalidity);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode imap_dophase_done(struct connectdata *conn, bool connected)
+{
+ struct IMAP *imap = conn->data->req.protop;
+
+ (void)connected;
+
+ if(imap->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode imap_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = imap_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = imap_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode imap_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct SessionHandle *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ /* Carry out the perform */
+ result = imap_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = imap_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode imap_setup_connection(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+
+ /* Initialise the IMAP layer */
+ CURLcode result = imap_init(conn);
+ if(result)
+ return result;
+
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel IMAP operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_imap)
+ conn->handler = &Curl_handler_imap_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_imaps_proxy;
+#else
+ failf(data, "IMAPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* set it up as an HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+#else
+ failf(data, "IMAP over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_sendf()
+ *
+ * Sends the formated string as an IMAP command to the server.
+ *
+ * Designed to never block.
+ */
+static CURLcode imap_sendf(struct connectdata *conn, const char *fmt, ...)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ char *taggedfmt;
+ va_list ap;
+
+ DEBUGASSERT(fmt);
+
+ /* Calculate the next command ID wrapping at 3 digits */
+ imapc->cmdid = (imapc->cmdid + 1) % 1000;
+
+ /* Calculate the tag based on the connection ID and command ID */
+ snprintf(imapc->resptag, sizeof(imapc->resptag), "%c%03d",
+ 'A' + curlx_sltosi(conn->connection_id % 26), imapc->cmdid);
+
+ /* Prefix the format with the tag */
+ taggedfmt = aprintf("%s %s", imapc->resptag, fmt);
+ if(!taggedfmt)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Send the data with the tag */
+ va_start(ap, fmt);
+ result = Curl_pp_vsendf(&imapc->pp, taggedfmt, ap);
+ va_end(ap);
+
+ Curl_safefree(taggedfmt);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_atom()
+ *
+ * Checks the input string for characters that need escaping and returns an
+ * atom ready for sending to the server.
+ *
+ * The returned string needs to be freed.
+ *
+ */
+static char *imap_atom(const char *str)
+{
+ const char *p1;
+ char *p2;
+ size_t backsp_count = 0;
+ size_t quote_count = 0;
+ bool space_exists = FALSE;
+ size_t newlen = 0;
+ char *newstr = NULL;
+
+ if(!str)
+ return NULL;
+
+ /* Count any unescapped characters */
+ p1 = str;
+ while(*p1) {
+ if(*p1 == '\\')
+ backsp_count++;
+ else if(*p1 == '"')
+ quote_count++;
+ else if(*p1 == ' ')
+ space_exists = TRUE;
+
+ p1++;
+ }
+
+ /* Does the input contain any unescapped characters? */
+ if(!backsp_count && !quote_count && !space_exists)
+ return strdup(str);
+
+ /* Calculate the new string length */
+ newlen = strlen(str) + backsp_count + quote_count + (space_exists ? 2 : 0);
+
+ /* Allocate the new string */
+ newstr = (char *) malloc((newlen + 1) * sizeof(char));
+ if(!newstr)
+ return NULL;
+
+ /* Surround the string in quotes if necessary */
+ p2 = newstr;
+ if(space_exists) {
+ newstr[0] = '"';
+ newstr[newlen - 1] = '"';
+ p2++;
+ }
+
+ /* Copy the string, escaping backslash and quote characters along the way */
+ p1 = str;
+ while(*p1) {
+ if(*p1 == '\\' || *p1 == '"') {
+ *p2 = '\\';
+ p2++;
+ }
+
+ *p2 = *p1;
+
+ p1++;
+ p2++;
+ }
+
+ /* Terminate the string */
+ newstr[newlen] = '\0';
+
+ return newstr;
+}
+
+/***********************************************************************
+ *
+ * imap_is_bchar()
+ *
+ * Portable test of whether the specified char is a "bchar" as defined in the
+ * grammar of RFC-5092.
+ */
+static bool imap_is_bchar(char ch)
+{
+ switch(ch) {
+ /* bchar */
+ case ':': case '@': case '/':
+ /* bchar -> achar */
+ case '&': case '=':
+ /* bchar -> achar -> uchar -> unreserved */
+ case '0': case '1': case '2': case '3': case '4': case '5': case '6':
+ case '7': case '8': case '9':
+ case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
+ case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
+ case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
+ case 'V': case 'W': case 'X': case 'Y': case 'Z':
+ case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
+ case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
+ case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
+ case 'v': case 'w': case 'x': case 'y': case 'z':
+ case '-': case '.': case '_': case '~':
+ /* bchar -> achar -> uchar -> sub-delims-sh */
+ case '!': case '$': case '\'': case '(': case ')': case '*':
+ case '+': case ',':
+ /* bchar -> achar -> uchar -> pct-encoded */
+ case '%': /* HEXDIG chars are already included above */
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode imap_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct imap_conn *imapc = &conn->proto.imapc;
+ const char *options = conn->options;
+ const char *ptr = options;
+
+ if(options) {
+ const char *key = ptr;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ if(strnequal(key, "AUTH", 4)) {
+ const char *value = ptr + 1;
+
+ if(strequal(value, "*"))
+ imapc->prefmech = SASL_AUTH_ANY;
+ else if(strequal(value, SASL_MECH_STRING_LOGIN))
+ imapc->prefmech = SASL_MECH_LOGIN;
+ else if(strequal(value, SASL_MECH_STRING_PLAIN))
+ imapc->prefmech = SASL_MECH_PLAIN;
+ else if(strequal(value, SASL_MECH_STRING_CRAM_MD5))
+ imapc->prefmech = SASL_MECH_CRAM_MD5;
+ else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5))
+ imapc->prefmech = SASL_MECH_DIGEST_MD5;
+ else if(strequal(value, SASL_MECH_STRING_GSSAPI))
+ imapc->prefmech = SASL_MECH_GSSAPI;
+ else if(strequal(value, SASL_MECH_STRING_NTLM))
+ imapc->prefmech = SASL_MECH_NTLM;
+ else if(strequal(value, SASL_MECH_STRING_XOAUTH2))
+ imapc->prefmech = SASL_MECH_XOAUTH2;
+ else
+ imapc->prefmech = SASL_AUTH_NONE;
+ }
+ else
+ result = CURLE_URL_MALFORMAT;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ *
+ */
+static CURLcode imap_parse_url_path(struct connectdata *conn)
+{
+ /* The imap struct is already initialised in imap_connect() */
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ const char *begin = data->state.path;
+ const char *ptr = begin;
+
+ /* See how much of the URL is a valid path and decode it */
+ while(imap_is_bchar(*ptr))
+ ptr++;
+
+ if(ptr != begin) {
+ /* Remove the trailing slash if present */
+ const char *end = ptr;
+ if(end > begin && end[-1] == '/')
+ end--;
+
+ result = Curl_urldecode(data, begin, end - begin, &imap->mailbox, NULL,
+ TRUE);
+ if(result)
+ return result;
+ }
+ else
+ imap->mailbox = NULL;
+
+ /* There can be any number of parameters in the form ";NAME=VALUE" */
+ while(*ptr == ';') {
+ char *name;
+ char *value;
+ size_t valuelen;
+
+ /* Find the length of the name parameter */
+ begin = ++ptr;
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ if(!*ptr)
+ return CURLE_URL_MALFORMAT;
+
+ /* Decode the name parameter */
+ result = Curl_urldecode(data, begin, ptr - begin, &name, NULL, TRUE);
+ if(result)
+ return result;
+
+ /* Find the length of the value parameter */
+ begin = ++ptr;
+ while(imap_is_bchar(*ptr))
+ ptr++;
+
+ /* Decode the value parameter */
+ result = Curl_urldecode(data, begin, ptr - begin, &value, &valuelen, TRUE);
+ if(result) {
+ Curl_safefree(name);
+ return result;
+ }
+
+ DEBUGF(infof(conn->data, "IMAP URL parameter '%s' = '%s'\n", name, value));
+
+ /* Process the known hierarchical parameters (UIDVALIDITY, UID and SECTION)
+ stripping of the trailing slash character if it is present.
+
+ Note: Unknown parameters trigger a URL_MALFORMAT error. */
+ if(Curl_raw_equal(name, "UIDVALIDITY") && !imap->uidvalidity) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->uidvalidity = value;
+ value = NULL;
+ }
+ else if(Curl_raw_equal(name, "UID") && !imap->uid) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->uid = value;
+ value = NULL;
+ }
+ else if(Curl_raw_equal(name, "SECTION") && !imap->section) {
+ if(valuelen > 0 && value[valuelen - 1] == '/')
+ value[valuelen - 1] = '\0';
+
+ imap->section = value;
+ value = NULL;
+ }
+ else {
+ Curl_safefree(name);
+ Curl_safefree(value);
+
+ return CURLE_URL_MALFORMAT;
+ }
+
+ Curl_safefree(name);
+ Curl_safefree(value);
+ }
+
+ /* Any extra stuff at the end of the URL is an error */
+ if(*ptr)
+ return CURLE_URL_MALFORMAT;
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * imap_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode imap_parse_custom_request(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct IMAP *imap = data->req.protop;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ if(custom) {
+ /* URL decode the custom request */
+ result = Curl_urldecode(data, custom, 0, &imap->custom, NULL, TRUE);
+
+ /* Extract the parameters if specified */
+ if(!result) {
+ const char *params = imap->custom;
+
+ while(*params && *params != ' ')
+ params++;
+
+ if(*params) {
+ imap->custom_params = strdup(params);
+ imap->custom[params - imap->custom] = '\0';
+
+ if(!imap->custom_params)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+ }
+
+ return result;
+}
+
+#endif /* CURL_DISABLE_IMAP */
diff --git a/libs/libcurl/src/imap.h b/libs/libcurl/src/imap.h
new file mode 100644
index 0000000000..1d4faabd70
--- /dev/null
+++ b/libs/libcurl/src/imap.h
@@ -0,0 +1,94 @@
+#ifndef HEADER_CURL_IMAP_H
+#define HEADER_CURL_IMAP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 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 "pingpong.h"
+
+/****************************************************************************
+ * IMAP unique setup
+ ***************************************************************************/
+typedef enum {
+ IMAP_STOP, /* do nothing state, stops the state machine */
+ IMAP_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ IMAP_CAPABILITY,
+ IMAP_STARTTLS,
+ IMAP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ IMAP_AUTHENTICATE_PLAIN,
+ IMAP_AUTHENTICATE_LOGIN,
+ IMAP_AUTHENTICATE_LOGIN_PASSWD,
+ IMAP_AUTHENTICATE_CRAMMD5,
+ IMAP_AUTHENTICATE_DIGESTMD5,
+ IMAP_AUTHENTICATE_DIGESTMD5_RESP,
+ IMAP_AUTHENTICATE_NTLM,
+ IMAP_AUTHENTICATE_NTLM_TYPE2MSG,
+ IMAP_AUTHENTICATE_XOAUTH2,
+ IMAP_AUTHENTICATE_FINAL,
+ IMAP_LOGIN,
+ IMAP_LIST,
+ IMAP_SELECT,
+ IMAP_FETCH,
+ IMAP_FETCH_FINAL,
+ IMAP_APPEND,
+ IMAP_APPEND_FINAL,
+ IMAP_LOGOUT,
+ IMAP_LAST /* never used */
+} imapstate;
+
+/* This IMAP struct is used in the SessionHandle. All IMAP data that is
+ connection-oriented must be in imap_conn to properly deal with the fact that
+ perhaps the SessionHandle is changed between the times the connection is
+ used. */
+struct IMAP {
+ curl_pp_transfer transfer;
+ char *mailbox; /* Mailbox to select */
+ char *uidvalidity; /* UIDVALIDITY to check in select */
+ char *uid; /* Message UID to fetch */
+ char *section; /* Message SECTION to fetch */
+ char *custom; /* Custom request */
+ char *custom_params; /* Parameters for the custom request */
+};
+
+/* imap_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct imap_conn {
+ struct pingpong pp;
+ imapstate state; /* Always use imap.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ unsigned int authmechs; /* Accepted authentication mechanisms */
+ unsigned int prefmech; /* Preferred authentication mechanism */
+ unsigned int authused; /* Auth mechanism used for the connection */
+ int cmdid; /* Last used command ID */
+ char resptag[5]; /* Response tag to wait for */
+ bool tls_supported; /* StartTLS capability supported by server */
+ bool login_disabled; /* LOGIN command disabled by server */
+ bool ir_supported; /* Initial response supported by server */
+ char *mailbox; /* The last selected mailbox */
+ char *mailbox_uidvalidity; /* UIDVALIDITY parsed from select response */
+};
+
+extern const struct Curl_handler Curl_handler_imap;
+extern const struct Curl_handler Curl_handler_imaps;
+
+#endif /* HEADER_CURL_IMAP_H */
diff --git a/libs/libcurl/src/inet_ntop.c b/libs/libcurl/src/inet_ntop.c
new file mode 100644
index 0000000000..c327150055
--- /dev/null
+++ b/libs/libcurl/src/inet_ntop.c
@@ -0,0 +1,199 @@
+/*
+ * Copyright (C) 1996-2001 Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM
+ * DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
+ * INTERNET SOFTWARE CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
+ * FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
+ * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
+ * WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * Original code by Paul Vixie. "curlified" by Gisle Vanem.
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_NTOP
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "inet_ntop.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/*
+ * Format an IPv4 address, more or less like inet_ntoa().
+ *
+ * Returns `dst' (as a const)
+ * Note:
+ * - uses no statics
+ * - takes a unsigned char* not an in_addr as input
+ */
+static char *inet_ntop4 (const unsigned char *src, char *dst, size_t size)
+{
+ char tmp[sizeof "255.255.255.255"];
+ size_t len;
+
+ DEBUGASSERT(size >= 16);
+
+ tmp[0] = '\0';
+ (void)snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+ ((int)((unsigned char)src[0])) & 0xff,
+ ((int)((unsigned char)src[1])) & 0xff,
+ ((int)((unsigned char)src[2])) & 0xff,
+ ((int)((unsigned char)src[3])) & 0xff);
+
+ len = strlen(tmp);
+ if(len == 0 || len >= size) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return dst;
+}
+
+#ifdef ENABLE_IPV6
+/*
+ * Convert IPv6 binary address into presentation (printable) format.
+ */
+static char *inet_ntop6 (const unsigned char *src, char *dst, size_t size)
+{
+ /*
+ * Note that int32_t and int16_t need only be "at least" large enough
+ * to contain a value of the specified size. On some systems, like
+ * Crays, there is no such thing as an integer variable with 16 bits.
+ * Keep this in mind if you think this function should have been coded
+ * to use pointer overlays. All the world's not a VAX.
+ */
+ char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
+ char *tp;
+ struct {
+ long base;
+ long len;
+ } best, cur;
+ unsigned long words[IN6ADDRSZ / INT16SZ];
+ int i;
+
+ /* Preprocess:
+ * Copy the input (bytewise) array into a wordwise array.
+ * Find the longest run of 0x00's in src[] for :: shorthanding.
+ */
+ memset(words, '\0', sizeof(words));
+ for(i = 0; i < IN6ADDRSZ; i++)
+ words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
+
+ best.base = -1;
+ cur.base = -1;
+ best.len = 0;
+ cur.len = 0;
+
+ for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ if(words[i] == 0) {
+ if(cur.base == -1)
+ cur.base = i, cur.len = 1;
+ else
+ cur.len++;
+ }
+ else if(cur.base != -1) {
+ if(best.base == -1 || cur.len > best.len)
+ best = cur;
+ cur.base = -1;
+ }
+ }
+ if((cur.base != -1) && (best.base == -1 || cur.len > best.len))
+ best = cur;
+ if(best.base != -1 && best.len < 2)
+ best.base = -1;
+ /* Format the result. */
+ tp = tmp;
+ for(i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
+ /* Are we inside the best run of 0x00's? */
+ if(best.base != -1 && i >= best.base && i < (best.base + best.len)) {
+ if(i == best.base)
+ *tp++ = ':';
+ continue;
+ }
+
+ /* Are we following an initial run of 0x00s or any real hex?
+ */
+ if(i != 0)
+ *tp++ = ':';
+
+ /* Is this address an encapsulated IPv4?
+ */
+ if(i == 6 && best.base == 0 &&
+ (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
+ if(!inet_ntop4(src+12, tp, sizeof(tmp) - (tp - tmp))) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ tp += strlen(tp);
+ break;
+ }
+ tp += snprintf(tp, 5, "%lx", words[i]);
+ }
+
+ /* Was it a trailing run of 0x00's?
+ */
+ if(best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
+ *tp++ = ':';
+ *tp++ = '\0';
+
+ /* Check for overflow, copy, and we're done.
+ */
+ if((size_t)(tp - tmp) > size) {
+ SET_ERRNO(ENOSPC);
+ return (NULL);
+ }
+ strcpy(dst, tmp);
+ return dst;
+}
+#endif /* ENABLE_IPV6 */
+
+/*
+ * Convert a network format address to presentation format.
+ *
+ * Returns pointer to presentation format address (`buf').
+ * Returns NULL on error and errno set with the specific
+ * error, EAFNOSUPPORT or ENOSPC.
+ *
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this function sets when returning NULL, not SOCKERRNO.
+ */
+char *Curl_inet_ntop(int af, const void *src, char *buf, size_t size)
+{
+ switch (af) {
+ case AF_INET:
+ return inet_ntop4((const unsigned char*)src, buf, size);
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ return inet_ntop6((const unsigned char*)src, buf, size);
+#endif
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return NULL;
+ }
+}
+#endif /* HAVE_INET_NTOP */
diff --git a/libs/libcurl/src/inet_ntop.h b/libs/libcurl/src/inet_ntop.h
new file mode 100644
index 0000000000..db28ed807a
--- /dev/null
+++ b/libs/libcurl/src/inet_ntop.h
@@ -0,0 +1,38 @@
+#ifndef HEADER_CURL_INET_NTOP_H
+#define HEADER_CURL_INET_NTOP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+char *Curl_inet_ntop(int af, const void *addr, char *buf, size_t size);
+
+#ifdef HAVE_INET_NTOP
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_ntop(af,addr,buf,size) \
+ inet_ntop(af,addr,buf,(curl_socklen_t)size)
+#endif
+
+#endif /* HEADER_CURL_INET_NTOP_H */
+
diff --git a/libs/libcurl/src/inet_pton.c b/libs/libcurl/src/inet_pton.c
new file mode 100644
index 0000000000..f50b365da6
--- /dev/null
+++ b/libs/libcurl/src/inet_pton.c
@@ -0,0 +1,234 @@
+/* This is from the BIND 4.9.4 release, modified to compile by itself */
+
+/* Copyright (c) 1996 by Internet Software Consortium.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS
+ * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE
+ * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
+ * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
+ * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+ * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
+ * SOFTWARE.
+ */
+
+#include "curl_setup.h"
+
+#ifndef HAVE_INET_PTON
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "inet_pton.h"
+
+#define IN6ADDRSZ 16
+#define INADDRSZ 4
+#define INT16SZ 2
+
+/*
+ * WARNING: Don't even consider trying to compile this on a system where
+ * sizeof(int) < 4. sizeof(int) > 4 is fine; all the world's not a VAX.
+ */
+
+static int inet_pton4(const char *src, unsigned char *dst);
+#ifdef ENABLE_IPV6
+static int inet_pton6(const char *src, unsigned char *dst);
+#endif
+
+/* int
+ * inet_pton(af, src, dst)
+ * convert from presentation format (which usually means ASCII printable)
+ * to network format (which is usually some kind of binary format).
+ * return:
+ * 1 if the address was valid for the specified address family
+ * 0 if the address wasn't valid (`dst' is untouched in this case)
+ * -1 if some other error occurred (`dst' is untouched in this case, too)
+ * notice:
+ * On Windows we store the error in the thread errno, not
+ * in the winsock error code. This is to avoid losing the
+ * actual last winsock error. So use macro ERRNO to fetch the
+ * errno this function sets when returning (-1), not SOCKERRNO.
+ * author:
+ * Paul Vixie, 1996.
+ */
+int
+Curl_inet_pton(int af, const char *src, void *dst)
+{
+ switch (af) {
+ case AF_INET:
+ return (inet_pton4(src, (unsigned char *)dst));
+#ifdef ENABLE_IPV6
+ case AF_INET6:
+ return (inet_pton6(src, (unsigned char *)dst));
+#endif
+ default:
+ SET_ERRNO(EAFNOSUPPORT);
+ return (-1);
+ }
+ /* NOTREACHED */
+}
+
+/* int
+ * inet_pton4(src, dst)
+ * like inet_aton() but without all the hexadecimal and shorthand.
+ * return:
+ * 1 if `src' is a valid dotted quad, else 0.
+ * notice:
+ * does not touch `dst' unless it's returning 1.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton4(const char *src, unsigned char *dst)
+{
+ static const char digits[] = "0123456789";
+ int saw_digit, octets, ch;
+ unsigned char tmp[INADDRSZ], *tp;
+
+ saw_digit = 0;
+ octets = 0;
+ tp = tmp;
+ *tp = 0;
+ while((ch = *src++) != '\0') {
+ const char *pch;
+
+ if((pch = strchr(digits, ch)) != NULL) {
+ unsigned int val = *tp * 10 + (unsigned int)(pch - digits);
+
+ if(saw_digit && *tp == 0)
+ return (0);
+ if(val > 255)
+ return (0);
+ *tp = (unsigned char)val;
+ if(! saw_digit) {
+ if(++octets > 4)
+ return (0);
+ saw_digit = 1;
+ }
+ }
+ else if(ch == '.' && saw_digit) {
+ if(octets == 4)
+ return (0);
+ *++tp = 0;
+ saw_digit = 0;
+ }
+ else
+ return (0);
+ }
+ if(octets < 4)
+ return (0);
+ memcpy(dst, tmp, INADDRSZ);
+ return (1);
+}
+
+#ifdef ENABLE_IPV6
+/* int
+ * inet_pton6(src, dst)
+ * convert presentation level address to network order binary form.
+ * return:
+ * 1 if `src' is a valid [RFC1884 2.2] address, else 0.
+ * notice:
+ * (1) does not touch `dst' unless it's returning 1.
+ * (2) :: in a full address is silently ignored.
+ * credit:
+ * inspired by Mark Andrews.
+ * author:
+ * Paul Vixie, 1996.
+ */
+static int
+inet_pton6(const char *src, unsigned char *dst)
+{
+ static const char xdigits_l[] = "0123456789abcdef",
+ xdigits_u[] = "0123456789ABCDEF";
+ unsigned char tmp[IN6ADDRSZ], *tp, *endp, *colonp;
+ const char *xdigits, *curtok;
+ int ch, saw_xdigit;
+ size_t val;
+
+ memset((tp = tmp), 0, IN6ADDRSZ);
+ endp = tp + IN6ADDRSZ;
+ colonp = NULL;
+ /* Leading :: requires some special handling. */
+ if(*src == ':')
+ if(*++src != ':')
+ return (0);
+ curtok = src;
+ saw_xdigit = 0;
+ val = 0;
+ while((ch = *src++) != '\0') {
+ const char *pch;
+
+ if((pch = strchr((xdigits = xdigits_l), ch)) == NULL)
+ pch = strchr((xdigits = xdigits_u), ch);
+ if(pch != NULL) {
+ val <<= 4;
+ val |= (pch - xdigits);
+ if(++saw_xdigit > 4)
+ return (0);
+ continue;
+ }
+ if(ch == ':') {
+ curtok = src;
+ if(!saw_xdigit) {
+ if(colonp)
+ return (0);
+ colonp = tp;
+ continue;
+ }
+ if(tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ saw_xdigit = 0;
+ val = 0;
+ continue;
+ }
+ if(ch == '.' && ((tp + INADDRSZ) <= endp) &&
+ inet_pton4(curtok, tp) > 0) {
+ tp += INADDRSZ;
+ saw_xdigit = 0;
+ break; /* '\0' was seen by inet_pton4(). */
+ }
+ return (0);
+ }
+ if(saw_xdigit) {
+ if(tp + INT16SZ > endp)
+ return (0);
+ *tp++ = (unsigned char) (val >> 8) & 0xff;
+ *tp++ = (unsigned char) val & 0xff;
+ }
+ if(colonp != NULL) {
+ /*
+ * Since some memmove()'s erroneously fail to handle
+ * overlapping regions, we'll do the shift by hand.
+ */
+ const ssize_t n = tp - colonp;
+ ssize_t i;
+
+ if(tp == endp)
+ return (0);
+ for(i = 1; i <= n; i++) {
+ *(endp - i) = *(colonp + n - i);
+ *(colonp + n - i) = 0;
+ }
+ tp = endp;
+ }
+ if(tp != endp)
+ return (0);
+ memcpy(dst, tmp, IN6ADDRSZ);
+ return (1);
+}
+#endif /* ENABLE_IPV6 */
+
+#endif /* HAVE_INET_PTON */
diff --git a/libs/libcurl/src/inet_pton.h b/libs/libcurl/src/inet_pton.h
new file mode 100644
index 0000000000..43c5491430
--- /dev/null
+++ b/libs/libcurl/src/inet_pton.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_INET_PTON_H
+#define HEADER_CURL_INET_PTON_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2005, 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"
+
+int Curl_inet_pton(int, const char *, void *);
+
+#ifdef HAVE_INET_PTON
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#define Curl_inet_pton(x,y,z) inet_pton(x,y,z)
+#endif
+
+#endif /* HEADER_CURL_INET_PTON_H */
+
diff --git a/libs/libcurl/src/krb4.c b/libs/libcurl/src/krb4.c
new file mode 100644
index 0000000000..3d789621d8
--- /dev/null
+++ b/libs/libcurl/src/krb4.c
@@ -0,0 +1,440 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. Martin's latest changes were done 2000-09-18.
+ *
+ * It has since been patched away like a madman by Daniel Stenberg to make it
+ * better applied to curl conditions, and to make it not use globals, pollute
+ * name space and more.
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999 Kungliga Tekniska Hgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2011 Daniel Stenberg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_KRB4
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#include <krb.h>
+#include <des.h>
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "sendf.h"
+#include "krb4.h"
+#include "inet_ntop.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define LOCAL_ADDR (&conn->local_addr)
+#define REMOTE_ADDR conn->ip_addr->ai_addr
+#define myctladdr LOCAL_ADDR
+#define hisctladdr REMOTE_ADDR
+
+struct krb4_data {
+ des_cblock key;
+ des_key_schedule schedule;
+ char name[ANAME_SZ];
+ char instance[INST_SZ];
+ char realm[REALM_SZ];
+};
+
+#ifndef HAVE_STRLCPY
+/* if it ever goes non-static, make it Curl_ prefixed! */
+static size_t
+strlcpy (char *dst, const char *src, size_t dst_sz)
+{
+ size_t n;
+ char *p;
+
+ for(p = dst, n = 0;
+ n + 1 < dst_sz && *src != '\0';
+ ++p, ++src, ++n)
+ *p = *src;
+ *p = '\0';
+ if(*src == '\0')
+ return n;
+ else
+ return n + strlen (src);
+}
+#else
+size_t strlcpy (char *dst, const char *src, size_t dst_sz);
+#endif
+
+static int
+krb4_check_prot(void *app_data, int level)
+{
+ app_data = NULL; /* prevent compiler warning */
+ if(level == PROT_CONFIDENTIAL)
+ return -1;
+ return 0;
+}
+
+static int
+krb4_decode(void *app_data, void *buf, int len, int level,
+ struct connectdata *conn)
+{
+ MSG_DAT m;
+ int e;
+ struct krb4_data *d = app_data;
+
+ if(level == PROT_SAFE)
+ e = krb_rd_safe(buf, len, &d->key,
+ (struct sockaddr_in *)REMOTE_ADDR,
+ (struct sockaddr_in *)LOCAL_ADDR, &m);
+ else
+ e = krb_rd_priv(buf, len, d->schedule, &d->key,
+ (struct sockaddr_in *)REMOTE_ADDR,
+ (struct sockaddr_in *)LOCAL_ADDR, &m);
+ if(e) {
+ struct SessionHandle *data = conn->data;
+ infof(data, "krb4_decode: %s\n", krb_get_err_text(e));
+ return -1;
+ }
+ memmove(buf, m.app_data, m.app_length);
+ return m.app_length;
+}
+
+static int
+krb4_overhead(void *app_data, int level, int len)
+{
+ /* no arguments are used, just init them to prevent compiler warnings */
+ app_data = NULL;
+ level = 0;
+ len = 0;
+ return 31;
+}
+
+static int
+krb4_encode(void *app_data, const void *from, int length, int level, void **to,
+ struct connectdata *conn)
+{
+ struct krb4_data *d = app_data;
+ *to = malloc(length + 31);
+ if(!*to)
+ return -1;
+ if(level == PROT_SAFE)
+ /* NOTE that the void* cast is safe, krb_mk_safe/priv don't modify the
+ * input buffer
+ */
+ return krb_mk_safe((void*)from, *to, length, &d->key,
+ (struct sockaddr_in *)LOCAL_ADDR,
+ (struct sockaddr_in *)REMOTE_ADDR);
+ else if(level == PROT_PRIVATE)
+ return krb_mk_priv((void*)from, *to, length, d->schedule, &d->key,
+ (struct sockaddr_in *)LOCAL_ADDR,
+ (struct sockaddr_in *)REMOTE_ADDR);
+ else
+ return -1;
+}
+
+static int
+mk_auth(struct krb4_data *d, KTEXT adat,
+ const char *service, char *host, int checksum)
+{
+ int ret;
+ CREDENTIALS cred;
+ char sname[SNAME_SZ], inst[INST_SZ], realm[REALM_SZ];
+
+ strlcpy(sname, service, sizeof(sname));
+ strlcpy(inst, krb_get_phost(host), sizeof(inst));
+ strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+ ret = krb_mk_req(adat, sname, inst, realm, checksum);
+ if(ret)
+ return ret;
+ strlcpy(sname, service, sizeof(sname));
+ strlcpy(inst, krb_get_phost(host), sizeof(inst));
+ strlcpy(realm, krb_realmofhost(host), sizeof(realm));
+ ret = krb_get_cred(sname, inst, realm, &cred);
+ memmove(&d->key, &cred.session, sizeof(des_cblock));
+ des_key_sched(&d->key, d->schedule);
+ memset(&cred, 0, sizeof(cred));
+ return ret;
+}
+
+#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
+int krb_get_our_ip_for_realm(char *, struct in_addr *);
+#endif
+
+static int
+krb4_auth(void *app_data, struct connectdata *conn)
+{
+ int ret;
+ char *p;
+ unsigned char *ptr;
+ size_t len = 0;
+ KTEXT_ST adat;
+ MSG_DAT msg_data;
+ int checksum;
+ u_int32_t cs;
+ struct krb4_data *d = app_data;
+ char *host = conn->host.name;
+ ssize_t nread;
+ int l = sizeof(conn->local_addr);
+ struct SessionHandle *data = conn->data;
+ CURLcode result;
+ size_t base64_sz = 0;
+
+ if(getsockname(conn->sock[FIRSTSOCKET],
+ (struct sockaddr *)LOCAL_ADDR, &l) < 0)
+ perror("getsockname()");
+
+ checksum = getpid();
+ ret = mk_auth(d, &adat, "ftp", host, checksum);
+ if(ret == KDC_PR_UNKNOWN)
+ ret = mk_auth(d, &adat, "rcmd", host, checksum);
+ if(ret) {
+ infof(data, "%s\n", krb_get_err_text(ret));
+ return AUTH_CONTINUE;
+ }
+
+#ifdef HAVE_KRB_GET_OUR_IP_FOR_REALM
+ if(krb_get_config_bool("nat_in_use")) {
+ struct sockaddr_in *localaddr = (struct sockaddr_in *)LOCAL_ADDR;
+ struct in_addr natAddr;
+
+ if(krb_get_our_ip_for_realm(krb_realmofhost(host),
+ &natAddr) != KSUCCESS
+ && krb_get_our_ip_for_realm(NULL, &natAddr) != KSUCCESS)
+ infof(data, "Can't get address for realm %s\n",
+ krb_realmofhost(host));
+ else {
+ if(natAddr.s_addr != localaddr->sin_addr.s_addr) {
+ char addr_buf[128];
+ if(Curl_inet_ntop(AF_INET, natAddr, addr_buf, sizeof(addr_buf)))
+ infof(data, "Using NAT IP address (%s) for kerberos 4\n", addr_buf);
+ localaddr->sin_addr = natAddr;
+ }
+ }
+ }
+#endif
+
+ result = Curl_base64_encode(conn->data, (char *)adat.dat, adat.length,
+ &p, &base64_sz);
+ if(result) {
+ Curl_failf(data, "base64-encoding: %s", curl_easy_strerror(result));
+ return AUTH_CONTINUE;
+ }
+
+ result = Curl_ftpsendf(conn, "ADAT %s", p);
+
+ free(p);
+
+ if(result)
+ return -2;
+
+ if(Curl_GetFTPResponse(&nread, conn, NULL))
+ return -1;
+
+ if(data->state.buffer[0] != '2') {
+ Curl_failf(data, "Server didn't accept auth data");
+ return AUTH_ERROR;
+ }
+
+ p = strstr(data->state.buffer, "ADAT=");
+ if(!p) {
+ Curl_failf(data, "Remote host didn't send adat reply");
+ return AUTH_ERROR;
+ }
+ p += 5;
+ result = Curl_base64_decode(p, &ptr, &len);
+ if(result) {
+ Curl_failf(data, "base64-decoding: %s", curl_easy_strerror(result));
+ return AUTH_ERROR;
+ }
+ if(len > sizeof(adat.dat)-1) {
+ free(ptr);
+ ptr = NULL;
+ len = 0;
+ }
+ if(!len || !ptr) {
+ Curl_failf(data, "Failed to decode base64 from server");
+ return AUTH_ERROR;
+ }
+ memcpy((char *)adat.dat, ptr, len);
+ free(ptr);
+ adat.length = len;
+ ret = krb_rd_safe(adat.dat, adat.length, &d->key,
+ (struct sockaddr_in *)hisctladdr,
+ (struct sockaddr_in *)myctladdr, &msg_data);
+ if(ret) {
+ Curl_failf(data, "Error reading reply from server: %s",
+ krb_get_err_text(ret));
+ return AUTH_ERROR;
+ }
+ krb_get_int(msg_data.app_data, &cs, 4, 0);
+ if(cs - checksum != 1) {
+ Curl_failf(data, "Bad checksum returned from server");
+ return AUTH_ERROR;
+ }
+ return AUTH_OK;
+}
+
+struct Curl_sec_client_mech Curl_krb4_client_mech = {
+ "KERBEROS_V4",
+ sizeof(struct krb4_data),
+ NULL, /* init */
+ krb4_auth,
+ NULL, /* end */
+ krb4_check_prot,
+ krb4_overhead,
+ krb4_encode,
+ krb4_decode
+};
+
+static enum protection_level
+krb4_set_command_prot(struct connectdata *conn, enum protection_level level)
+{
+ enum protection_level old = conn->command_prot;
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+ conn->command_prot = level;
+ return old;
+}
+
+CURLcode Curl_krb_kauth(struct connectdata *conn)
+{
+ des_cblock key;
+ des_key_schedule schedule;
+ KTEXT_ST tkt, tktcopy;
+ char *name;
+ char *p;
+ char passwd[100];
+ size_t tmp = 0;
+ ssize_t nread;
+ enum protection_level save;
+ CURLcode result;
+ unsigned char *ptr;
+ size_t base64_sz = 0;
+
+ save = krb4_set_command_prot(conn, PROT_PRIVATE);
+
+ result = Curl_ftpsendf(conn, "SITE KAUTH %s", conn->user);
+
+ if(result)
+ return result;
+
+ result = Curl_GetFTPResponse(&nread, conn, NULL);
+ if(result)
+ return result;
+
+ if(conn->data->state.buffer[0] != '3') {
+ krb4_set_command_prot(conn, save);
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+
+ p = strstr(conn->data->state.buffer, "T=");
+ if(!p) {
+ Curl_failf(conn->data, "Bad reply from server");
+ krb4_set_command_prot(conn, save);
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+
+ p += 2;
+ result = Curl_base64_decode(p, &ptr, &tmp);
+ if(result) {
+ Curl_failf(conn->data, "base64-decoding: %s", curl_easy_strerror(result));
+ return result;
+ }
+ if(tmp >= sizeof(tkt.dat)) {
+ free(ptr);
+ ptr = NULL;
+ tmp = 0;
+ }
+ if(!tmp || !ptr) {
+ Curl_failf(conn->data, "Failed to decode base64 in reply");
+ krb4_set_command_prot(conn, save);
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+ memcpy((char *)tkt.dat, ptr, tmp);
+ free(ptr);
+ tkt.length = tmp;
+ tktcopy.length = tkt.length;
+
+ p = strstr(conn->data->state.buffer, "P=");
+ if(!p) {
+ Curl_failf(conn->data, "Bad reply from server");
+ krb4_set_command_prot(conn, save);
+ return CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+ name = p + 2;
+ for(; *p && *p != ' ' && *p != '\r' && *p != '\n'; p++);
+ *p = 0;
+
+ des_string_to_key (conn->passwd, &key);
+ des_key_sched(&key, schedule);
+
+ des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
+ tkt.length,
+ schedule, &key, DES_DECRYPT);
+ if(strcmp ((char*)tktcopy.dat + 8,
+ KRB_TICKET_GRANTING_TICKET) != 0) {
+ afs_string_to_key(passwd,
+ krb_realmofhost(conn->host.name),
+ &key);
+ des_key_sched(&key, schedule);
+ des_pcbc_encrypt((void *)tkt.dat, (void *)tktcopy.dat,
+ tkt.length,
+ schedule, &key, DES_DECRYPT);
+ }
+ memset(key, 0, sizeof(key));
+ memset(schedule, 0, sizeof(schedule));
+ memset(passwd, 0, sizeof(passwd));
+ result = Curl_base64_encode(conn->data, (char *)tktcopy.dat, tktcopy.length,
+ &p, &base64_sz);
+ if(result) {
+ Curl_failf(conn->data, "base64-encoding: %s", curl_easy_strerror(result));
+ krb4_set_command_prot(conn, save);
+ return result;
+ }
+ memset (tktcopy.dat, 0, tktcopy.length);
+
+ result = Curl_ftpsendf(conn, "SITE KAUTH %s %s", name, p);
+ free(p);
+ if(result)
+ return result;
+
+ result = Curl_GetFTPResponse(&nread, conn, NULL);
+ if(result)
+ return result;
+ krb4_set_command_prot(conn, save);
+
+ return CURLE_OK;
+}
+
+#endif /* HAVE_KRB4 */
+#endif /* CURL_DISABLE_FTP */
diff --git a/libs/libcurl/src/krb4.h b/libs/libcurl/src/krb4.h
new file mode 100644
index 0000000000..3e29b25882
--- /dev/null
+++ b/libs/libcurl/src/krb4.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_KRB4_H
+#define HEADER_CURL_KRB4_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+struct Curl_sec_client_mech {
+ const char *name;
+ size_t size;
+ int (*init)(void *);
+ int (*auth)(void *, struct connectdata *);
+ void (*end)(void *);
+ int (*check_prot)(void *, int);
+ int (*overhead)(void *, int, int);
+ int (*encode)(void *, const void*, int, int, void**, struct connectdata *);
+ 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 */
+
diff --git a/libs/libcurl/src/krb5.c b/libs/libcurl/src/krb5.c
new file mode 100644
index 0000000000..1643f11a6a
--- /dev/null
+++ b/libs/libcurl/src/krb5.c
@@ -0,0 +1,341 @@
+/* GSSAPI/krb5 support for FTP - loosely based on old krb4.c
+ *
+ * Copyright (c) 1995, 1996, 1997, 1998, 1999, 2013 Kungliga Tekniska Hgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ * Copyright (c) 2004 - 2012 Daniel Stenberg
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#define NCOMPAT 1
+#endif
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "ftp.h"
+#include "curl_gssapi.h"
+#include "sendf.h"
+#include "curl_sec.h"
+#include "curl_memory.h"
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define LOCAL_ADDR (&conn->local_addr)
+#define REMOTE_ADDR conn->ip_addr->ai_addr
+
+static int
+krb5_init(void *app_data)
+{
+ gss_ctx_id_t *context = app_data;
+ /* Make sure our context is initialized for krb5_end. */
+ *context = GSS_C_NO_CONTEXT;
+ return 0;
+}
+
+static int
+krb5_check_prot(void *app_data, int level)
+{
+ (void)app_data; /* unused */
+ if(level == PROT_CONFIDENTIAL)
+ return -1;
+ return 0;
+}
+
+static int
+krb5_decode(void *app_data, void *buf, int len,
+ int level UNUSED_PARAM,
+ struct connectdata *conn UNUSED_PARAM)
+{
+ gss_ctx_id_t *context = app_data;
+ OM_uint32 maj, min;
+ gss_buffer_desc enc, dec;
+
+ (void)level;
+ (void)conn;
+
+ enc.value = buf;
+ enc.length = len;
+ maj = gss_unseal(&min, *context, &enc, &dec, NULL, NULL);
+ if(maj != GSS_S_COMPLETE) {
+ if(len >= 4)
+ strcpy(buf, "599 ");
+ return -1;
+ }
+
+ memcpy(buf, dec.value, dec.length);
+ len = curlx_uztosi(dec.length);
+ gss_release_buffer(&min, &dec);
+
+ return len;
+}
+
+static int
+krb5_overhead(void *app_data, int level, int len)
+{
+ /* no arguments are used */
+ (void)app_data;
+ (void)level;
+ (void)len;
+ return 0;
+}
+
+static int
+krb5_encode(void *app_data, const void *from, int length, int level, void **to,
+ struct connectdata *conn UNUSED_PARAM)
+{
+ gss_ctx_id_t *context = app_data;
+ gss_buffer_desc dec, enc;
+ OM_uint32 maj, min;
+ int state;
+ int len;
+
+ /* shut gcc up */
+ conn = NULL;
+
+ /* NOTE that the cast is safe, neither of the krb5, gnu gss and heimdal
+ * libraries modify the input buffer in gss_seal()
+ */
+ dec.value = (void*)from;
+ dec.length = length;
+ maj = gss_seal(&min, *context,
+ level == PROT_PRIVATE,
+ GSS_C_QOP_DEFAULT,
+ &dec, &state, &enc);
+
+ if(maj != GSS_S_COMPLETE)
+ return -1;
+
+ /* malloc a new buffer, in case gss_release_buffer doesn't work as
+ expected */
+ *to = malloc(enc.length);
+ if(!*to)
+ return -1;
+ memcpy(*to, enc.value, enc.length);
+ len = curlx_uztosi(enc.length);
+ gss_release_buffer(&min, &enc);
+ return len;
+}
+
+static int
+krb5_auth(void *app_data, struct connectdata *conn)
+{
+ int ret = AUTH_OK;
+ char *p;
+ const char *host = conn->host.name;
+ ssize_t nread;
+ curl_socklen_t l = sizeof(conn->local_addr);
+ struct SessionHandle *data = conn->data;
+ CURLcode result;
+ const char *service = "ftp", *srv_host = "host";
+ gss_buffer_desc input_buffer, output_buffer, _gssresp, *gssresp;
+ OM_uint32 maj, min;
+ gss_name_t gssname;
+ gss_ctx_id_t *context = app_data;
+ struct gss_channel_bindings_struct chan;
+ size_t base64_sz = 0;
+
+ if(getsockname(conn->sock[FIRSTSOCKET],
+ (struct sockaddr *)LOCAL_ADDR, &l) < 0)
+ perror("getsockname()");
+
+ chan.initiator_addrtype = GSS_C_AF_INET;
+ chan.initiator_address.length = l - 4;
+ chan.initiator_address.value =
+ &((struct sockaddr_in *)LOCAL_ADDR)->sin_addr.s_addr;
+ chan.acceptor_addrtype = GSS_C_AF_INET;
+ chan.acceptor_address.length = l - 4;
+ chan.acceptor_address.value =
+ &((struct sockaddr_in *)REMOTE_ADDR)->sin_addr.s_addr;
+ chan.application_data.length = 0;
+ chan.application_data.value = NULL;
+
+ /* this loop will execute twice (once for service, once for host) */
+ for(;;) {
+ /* this really shouldn't be repeated here, but can't help it */
+ if(service == srv_host) {
+ result = Curl_ftpsendf(conn, "AUTH GSSAPI");
+
+ if(result)
+ return -2;
+ if(Curl_GetFTPResponse(&nread, conn, NULL))
+ return -1;
+
+ if(data->state.buffer[0] != '3')
+ return -1;
+ }
+
+ input_buffer.value = data->state.buffer;
+ input_buffer.length = snprintf(input_buffer.value, BUFSIZE, "%s@%s",
+ service, host);
+ maj = gss_import_name(&min, &input_buffer, GSS_C_NT_HOSTBASED_SERVICE,
+ &gssname);
+ if(maj != GSS_S_COMPLETE) {
+ gss_release_name(&min, &gssname);
+ if(service == srv_host) {
+ Curl_failf(data, "Error importing service name %s",
+ input_buffer.value);
+ return AUTH_ERROR;
+ }
+ service = srv_host;
+ continue;
+ }
+ /* We pass NULL as |output_name_type| to avoid a leak. */
+ gss_display_name(&min, gssname, &output_buffer, NULL);
+ Curl_infof(data, "Trying against %s\n", output_buffer.value);
+ gssresp = GSS_C_NO_BUFFER;
+ *context = GSS_C_NO_CONTEXT;
+
+ do {
+ /* Release the buffer at each iteration to avoid leaking: the first time
+ we are releasing the memory from gss_display_name. The last item is
+ taken care by a final gss_release_buffer. */
+ gss_release_buffer(&min, &output_buffer);
+ ret = AUTH_OK;
+ maj = Curl_gss_init_sec_context(data,
+ &min,
+ context,
+ gssname,
+ &chan,
+ gssresp,
+ &output_buffer,
+ NULL);
+
+ if(gssresp) {
+ free(_gssresp.value);
+ gssresp = NULL;
+ }
+
+ if(GSS_ERROR(maj)) {
+ Curl_infof(data, "Error creating security context\n");
+ ret = AUTH_ERROR;
+ break;
+ }
+
+ if(output_buffer.length != 0) {
+ result = Curl_base64_encode(data, (char *)output_buffer.value,
+ output_buffer.length, &p, &base64_sz);
+ if(result) {
+ Curl_infof(data,"base64-encoding: %s\n", curl_easy_strerror(result));
+ ret = AUTH_CONTINUE;
+ break;
+ }
+
+ result = Curl_ftpsendf(conn, "ADAT %s", p);
+
+ free(p);
+
+ if(result) {
+ ret = -2;
+ break;
+ }
+
+ if(Curl_GetFTPResponse(&nread, conn, NULL)) {
+ ret = -1;
+ break;
+ }
+
+ if(data->state.buffer[0] != '2' && data->state.buffer[0] != '3') {
+ Curl_infof(data, "Server didn't accept auth data\n");
+ ret = AUTH_ERROR;
+ break;
+ }
+
+ p = data->state.buffer + 4;
+ p = strstr(p, "ADAT=");
+ if(p) {
+ result = Curl_base64_decode(p + 5,
+ (unsigned char **)&_gssresp.value,
+ &_gssresp.length);
+ if(result) {
+ Curl_failf(data,"base64-decoding: %s", curl_easy_strerror(result));
+ ret = AUTH_CONTINUE;
+ break;
+ }
+ }
+
+ gssresp = &_gssresp;
+ }
+ } while(maj == GSS_S_CONTINUE_NEEDED);
+
+ gss_release_name(&min, &gssname);
+ gss_release_buffer(&min, &output_buffer);
+
+ if(gssresp)
+ free(_gssresp.value);
+
+ if(ret == AUTH_OK || service == srv_host)
+ return ret;
+
+ service = srv_host;
+ }
+ return ret;
+}
+
+static void krb5_end(void *app_data)
+{
+ OM_uint32 min;
+ gss_ctx_id_t *context = app_data;
+ if(*context != GSS_C_NO_CONTEXT) {
+#ifdef DEBUGBUILD
+ OM_uint32 maj =
+#endif
+ gss_delete_sec_context(&min, context, GSS_C_NO_BUFFER);
+ DEBUGASSERT(maj == GSS_S_COMPLETE);
+ }
+}
+
+struct Curl_sec_client_mech Curl_krb5_client_mech = {
+ "GSSAPI",
+ sizeof(gss_ctx_id_t),
+ krb5_init,
+ krb5_auth,
+ krb5_end,
+ krb5_check_prot,
+ krb5_overhead,
+ krb5_encode,
+ krb5_decode
+};
+
+#endif /* HAVE_GSSAPI */
+#endif /* CURL_DISABLE_FTP */
diff --git a/libs/libcurl/src/ldap.c b/libs/libcurl/src/ldap.c
new file mode 100644
index 0000000000..c2fa1735fa
--- /dev/null
+++ b/libs/libcurl/src/ldap.c
@@ -0,0 +1,708 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+#ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */
+# include <winldap.h>
+# ifndef LDAP_VENDOR_NAME
+# error Your Platform SDK is NOT sufficient for LDAP support! \
+ Update your Platform SDK, or disable LDAP support!
+# else
+# include <winber.h>
+# endif
+#else
+# define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */
+# ifdef HAVE_LBER_H
+# include <lber.h>
+# endif
+# include <ldap.h>
+# if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
+# include <ldap_ssl.h>
+# endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "escape.h"
+#include "progress.h"
+#include "transfer.h"
+#include "strequal.h"
+#include "strtok.h"
+#include "curl_ldap.h"
+#include "curl_memory.h"
+#include "curl_base64.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "memdebug.h"
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/* Use our own implementation. */
+
+typedef struct {
+ char *lud_host;
+ int lud_port;
+ char *lud_dn;
+ char **lud_attrs;
+ int lud_scope;
+ char *lud_filter;
+ char **lud_exts;
+ size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the
+ "real" struct so can only be used in code
+ without HAVE_LDAP_URL_PARSE defined */
+} CURL_LDAPURLDesc;
+
+#undef LDAPURLDesc
+#define LDAPURLDesc CURL_LDAPURLDesc
+
+static int _ldap_url_parse (const struct connectdata *conn,
+ LDAPURLDesc **ludp);
+static void _ldap_free_urldesc (LDAPURLDesc *ludp);
+
+#undef ldap_free_urldesc
+#define ldap_free_urldesc _ldap_free_urldesc
+#endif
+
+#ifdef DEBUG_LDAP
+ #define LDAP_TRACE(x) do { \
+ _ldap_trace ("%u: ", __LINE__); \
+ _ldap_trace x; \
+ } WHILE_FALSE
+
+ static void _ldap_trace (const char *fmt, ...);
+#else
+ #define LDAP_TRACE(x) Curl_nop_stmt
+#endif
+
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+ "LDAP", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_ldap, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAP, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef HAVE_LDAP_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+ "LDAPS", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ Curl_ldap, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAPS, /* defport */
+ CURLPROTO_LDAP | CURLPROTO_LDAPS, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#endif
+
+
+static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
+{
+ CURLcode status = CURLE_OK;
+ int rc = 0;
+ LDAP *server = NULL;
+ LDAPURLDesc *ludp = NULL;
+ LDAPMessage *result = NULL;
+ LDAPMessage *entryIterator;
+ int num = 0;
+ struct SessionHandle *data=conn->data;
+ int ldap_proto = LDAP_VERSION3;
+ int ldap_ssl = 0;
+ char *val_b64 = NULL;
+ size_t val_b64_sz = 0;
+ curl_off_t dlsize = 0;
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */
+#endif
+
+ *done = TRUE; /* unconditionally */
+ infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
+ LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
+ infof(data, "LDAP local: %s\n", data->change.url);
+
+#ifdef HAVE_LDAP_URL_PARSE
+ rc = ldap_url_parse(data->change.url, &ludp);
+#else
+ rc = _ldap_url_parse(conn, &ludp);
+#endif
+ if(rc != 0) {
+ failf(data, "LDAP local: %s", ldap_err2string(rc));
+ status = CURLE_LDAP_INVALID_URL;
+ goto quit;
+ }
+
+ /* Get the URL scheme ( either ldap or ldaps ) */
+ if(conn->given->flags & PROTOPT_SSL)
+ ldap_ssl = 1;
+ infof(data, "LDAP local: trying to establish %s connection\n",
+ ldap_ssl ? "encrypted" : "cleartext");
+
+#ifdef LDAP_OPT_NETWORK_TIMEOUT
+ ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
+#endif
+ ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+
+ if(ldap_ssl) {
+#ifdef HAVE_LDAP_SSL
+#ifdef CURL_LDAP_WIN
+ /* Win32 LDAP SDK doesn't support insecure mode without CA! */
+ server = ldap_sslinit(conn->host.name, (int)conn->port, 1);
+ ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
+#else
+ int ldap_option;
+ char* ldap_ca = data->set.str[STRING_SSL_CAFILE];
+#if defined(CURL_HAS_NOVELL_LDAPSDK)
+ rc = ldapssl_client_init(NULL, NULL);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ if(data->set.ssl.verifypeer) {
+ /* Novell SDK supports DER or BASE64 files. */
+ int cert_type = LDAPSSL_CERT_FILETYPE_B64;
+ if((data->set.str[STRING_CERT_TYPE]) &&
+ (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER")))
+ cert_type = LDAPSSL_CERT_FILETYPE_DER;
+ if(!ldap_ca) {
+ failf(data, "LDAP local: ERROR %s CA cert not set!",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ infof(data, "LDAP local: using %s CA cert '%s'\n",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_ca);
+ rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting %s CA cert: %s",
+ (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ ldap_option = LDAPSSL_VERIFY_SERVER;
+ }
+ else
+ ldap_option = LDAPSSL_VERIFY_NONE;
+ rc = ldapssl_set_verify_mode(ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ server = ldapssl_init(conn->host.name, (int)conn->port, 1);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.name, conn->port);
+ status = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+#elif defined(LDAP_OPT_X_TLS)
+ if(data->set.ssl.verifypeer) {
+ /* OpenLDAP SDK supports BASE64 files. */
+ if((data->set.str[STRING_CERT_TYPE]) &&
+ (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) {
+ failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ if(!ldap_ca) {
+ failf(data, "LDAP local: ERROR PEM CA cert not set!");
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ ldap_option = LDAP_OPT_X_TLS_DEMAND;
+ }
+ else
+ ldap_option = LDAP_OPT_X_TLS_NEVER;
+
+ rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting cert verify mode: %s",
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+ server = ldap_init(conn->host.name, (int)conn->port);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.name, conn->port);
+ status = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+ ldap_option = LDAP_OPT_X_TLS_HARD;
+ rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+/*
+ rc = ldap_start_tls_s(server, NULL, NULL);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
+ ldap_err2string(rc));
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+ }
+*/
+#else
+ /* we should probably never come up to here since configure
+ should check in first place if we can support LDAP SSL/TLS */
+ failf(data, "LDAP local: SSL/TLS not supported with this version "
+ "of the OpenLDAP toolkit\n");
+ status = CURLE_SSL_CERTPROBLEM;
+ goto quit;
+#endif
+#endif
+#endif /* CURL_LDAP_USE_SSL */
+ }
+ else {
+ server = ldap_init(conn->host.name, (int)conn->port);
+ if(server == NULL) {
+ failf(data, "LDAP local: Cannot connect to %s:%ld",
+ conn->host.name, conn->port);
+ status = CURLE_COULDNT_CONNECT;
+ goto quit;
+ }
+ }
+#ifdef CURL_LDAP_WIN
+ ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+#endif
+
+ rc = ldap_simple_bind_s(server,
+ conn->bits.user_passwd ? conn->user : NULL,
+ conn->bits.user_passwd ? conn->passwd : NULL);
+ if(!ldap_ssl && rc != 0) {
+ ldap_proto = LDAP_VERSION2;
+ ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
+ rc = ldap_simple_bind_s(server,
+ conn->bits.user_passwd ? conn->user : NULL,
+ conn->bits.user_passwd ? conn->passwd : NULL);
+ }
+ if(rc != 0) {
+ failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
+ status = CURLE_LDAP_CANNOT_BIND;
+ goto quit;
+ }
+
+ rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0, &result);
+
+ if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
+ failf(data, "LDAP remote: %s", ldap_err2string(rc));
+ status = CURLE_LDAP_SEARCH_FAILED;
+ goto quit;
+ }
+
+ for(num = 0, entryIterator = ldap_first_entry(server, result);
+ entryIterator;
+ entryIterator = ldap_next_entry(server, entryIterator), num++) {
+ BerElement *ber = NULL;
+ char *attribute; /*! suspicious that this isn't 'const' */
+ char *dn = ldap_get_dn(server, entryIterator);
+ int i;
+
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+
+ dlsize += strlen(dn)+5;
+
+ for(attribute = ldap_first_attribute(server, entryIterator, &ber);
+ attribute;
+ attribute = ldap_next_attribute(server, entryIterator, ber)) {
+ BerValue **vals = ldap_get_values_len(server, entryIterator, attribute);
+
+ if(vals != NULL) {
+ for(i = 0; (vals[i] != NULL); i++) {
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+ dlsize += strlen(attribute)+3;
+
+ if((strlen(attribute) > 7) &&
+ (strcmp(";binary",
+ (char *)attribute +
+ (strlen((char *)attribute) - 7)) == 0)) {
+ /* Binary attribute, encode to base64. */
+ CURLcode error = Curl_base64_encode(data,
+ vals[i]->bv_val,
+ vals[i]->bv_len,
+ &val_b64,
+ &val_b64_sz);
+ if(error) {
+ ldap_value_free_len(vals);
+ ldap_memfree(attribute);
+ ldap_memfree(dn);
+ if(ber)
+ ber_free(ber, 0);
+ status = error;
+ goto quit;
+ }
+ if(val_b64_sz > 0) {
+ Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
+ free(val_b64);
+ dlsize += val_b64_sz;
+ }
+ }
+ else {
+ Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
+ vals[i]->bv_len);
+ dlsize += vals[i]->bv_len;
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ dlsize++;
+ }
+
+ /* Free memory used to store values */
+ ldap_value_free_len(vals);
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ dlsize++;
+ Curl_pgrsSetDownloadCounter(data, dlsize);
+ ldap_memfree(attribute);
+ }
+ ldap_memfree(dn);
+ if(ber)
+ ber_free(ber, 0);
+ }
+
+quit:
+ if(result) {
+ ldap_msgfree(result);
+ LDAP_TRACE (("Received %d entries\n", num));
+ }
+ if(rc == LDAP_SIZELIMIT_EXCEEDED)
+ infof(data, "There are more than %d entries\n", num);
+ if(ludp)
+ ldap_free_urldesc(ludp);
+ if(server)
+ ldap_unbind_s(server);
+#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
+ if(ldap_ssl)
+ ldapssl_client_deinit();
+#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ conn->bits.close = TRUE;
+
+ return status;
+}
+
+#ifdef DEBUG_LDAP
+static void _ldap_trace (const char *fmt, ...)
+{
+ static int do_trace = -1;
+ va_list args;
+
+ if(do_trace == -1) {
+ const char *env = getenv("CURL_TRACE");
+ do_trace = (env && strtol(env, NULL, 10) > 0);
+ }
+ if(!do_trace)
+ return;
+
+ va_start (args, fmt);
+ vfprintf (stderr, fmt, args);
+ va_end (args);
+}
+#endif
+
+#ifndef HAVE_LDAP_URL_PARSE
+
+/*
+ * Return scope-value for a scope-string.
+ */
+static int str2scope (const char *p)
+{
+ if(strequal(p, "one"))
+ return LDAP_SCOPE_ONELEVEL;
+ if(strequal(p, "onetree"))
+ return LDAP_SCOPE_ONELEVEL;
+ if(strequal(p, "base"))
+ return LDAP_SCOPE_BASE;
+ if(strequal(p, "sub"))
+ return LDAP_SCOPE_SUBTREE;
+ if(strequal( p, "subtree"))
+ return LDAP_SCOPE_SUBTREE;
+ return (-1);
+}
+
+/*
+ * Split 'str' into strings separated by commas.
+ * Note: res[] points into 'str'.
+ */
+static char **split_str (char *str)
+{
+ char **res, *lasts, *s;
+ int i;
+
+ for(i = 2, s = strchr(str,','); s; i++)
+ s = strchr(++s,',');
+
+ res = calloc(i, sizeof(char*));
+ if(!res)
+ return NULL;
+
+ for(i = 0, s = strtok_r(str, ",", &lasts); s;
+ s = strtok_r(NULL, ",", &lasts), i++)
+ res[i] = s;
+ return res;
+}
+
+/*
+ * Unescape the LDAP-URL components
+ */
+static bool unescape_elements (void *data, LDAPURLDesc *ludp)
+{
+ int i;
+
+ if(ludp->lud_filter) {
+ ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL);
+ if(!ludp->lud_filter)
+ return FALSE;
+ }
+
+ for(i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) {
+ ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i],
+ 0, NULL);
+ if(!ludp->lud_attrs[i])
+ return FALSE;
+ ludp->lud_attrs_dups++;
+ }
+
+ if(ludp->lud_dn) {
+ char *dn = ludp->lud_dn;
+ char *new_dn = curl_easy_unescape(data, dn, 0, NULL);
+
+ free(dn);
+ ludp->lud_dn = new_dn;
+ if(!new_dn)
+ return (FALSE);
+ }
+ return (TRUE);
+}
+
+/*
+ * Break apart the pieces of an LDAP URL.
+ * Syntax:
+ * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
+ *
+ * <hostname> already known from 'conn->host.name'.
+ * <port> already known from 'conn->remote_port'.
+ * extract the rest from 'conn->data->state.path+1'. All fields are optional.
+ * e.g.
+ * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
+ * yields ludp->lud_dn = "".
+ *
+ * Defined in RFC4516 section 2.
+ */
+static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp)
+{
+ char *p, *q;
+ int i;
+
+ if(!conn->data ||
+ !conn->data->state.path ||
+ conn->data->state.path[0] != '/' ||
+ !checkprefix("LDAP", conn->data->change.url))
+ return LDAP_INVALID_SYNTAX;
+
+ ludp->lud_scope = LDAP_SCOPE_BASE;
+ ludp->lud_port = conn->remote_port;
+ ludp->lud_host = conn->host.name;
+
+ /* parse DN (Distinguished Name).
+ */
+ ludp->lud_dn = strdup(conn->data->state.path+1);
+ if(!ludp->lud_dn)
+ return LDAP_NO_MEMORY;
+
+ p = strchr(ludp->lud_dn, '?');
+ LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) :
+ strlen(ludp->lud_dn), ludp->lud_dn));
+
+ if(!p)
+ goto success;
+
+ *p++ = '\0';
+
+ /* parse attributes. skip "??".
+ */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p && *p != '?') {
+ ludp->lud_attrs = split_str(p);
+ if(!ludp->lud_attrs)
+ return LDAP_NO_MEMORY;
+
+ for(i = 0; ludp->lud_attrs[i]; i++)
+ LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i]));
+ }
+
+ p = q;
+ if(!p)
+ goto success;
+
+ /* parse scope. skip "??"
+ */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+
+ if(*p && *p != '?') {
+ ludp->lud_scope = str2scope(p);
+ if(ludp->lud_scope == -1) {
+ return LDAP_INVALID_SYNTAX;
+ }
+ LDAP_TRACE (("scope %d\n", ludp->lud_scope));
+ }
+
+ p = q;
+ if(!p)
+ goto success;
+
+ /* parse filter
+ */
+ q = strchr(p, '?');
+ if(q)
+ *q++ = '\0';
+ if(!*p) {
+ return LDAP_INVALID_SYNTAX;
+ }
+
+ ludp->lud_filter = p;
+ LDAP_TRACE (("filter '%s'\n", ludp->lud_filter));
+
+ success:
+ if(!unescape_elements(conn->data, ludp))
+ return LDAP_NO_MEMORY;
+ return LDAP_SUCCESS;
+}
+
+static int _ldap_url_parse (const struct connectdata *conn,
+ LDAPURLDesc **ludpp)
+{
+ LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
+ int rc;
+
+ *ludpp = NULL;
+ if(!ludp)
+ return LDAP_NO_MEMORY;
+
+ rc = _ldap_url_parse2 (conn, ludp);
+ if(rc != LDAP_SUCCESS) {
+ _ldap_free_urldesc(ludp);
+ ludp = NULL;
+ }
+ *ludpp = ludp;
+ return (rc);
+}
+
+static void _ldap_free_urldesc (LDAPURLDesc *ludp)
+{
+ size_t i;
+
+ if(!ludp)
+ return;
+
+ if(ludp->lud_dn)
+ free(ludp->lud_dn);
+
+ if(ludp->lud_filter)
+ free(ludp->lud_filter);
+
+ if(ludp->lud_attrs) {
+ for(i = 0; i < ludp->lud_attrs_dups; i++)
+ free(ludp->lud_attrs[i]);
+ free(ludp->lud_attrs);
+ }
+
+ free (ludp);
+}
+#endif /* !HAVE_LDAP_URL_PARSE */
+#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */
diff --git a/libs/libcurl/src/libcurl.rc b/libs/libcurl/src/libcurl.rc
new file mode 100644
index 0000000000..47b944ac86
--- /dev/null
+++ b/libs/libcurl/src/libcurl.rc
@@ -0,0 +1,63 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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 <winver.h>
+#include "../include/curl/curlver.h"
+
+LANGUAGE 0x09,0x01
+
+#define RC_VERSION LIBCURL_VERSION_MAJOR, LIBCURL_VERSION_MINOR, LIBCURL_VERSION_PATCH, 0
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION RC_VERSION
+ PRODUCTVERSION RC_VERSION
+ FILEFLAGSMASK 0x3fL
+#if defined(DEBUGBUILD) || defined(_DEBUG)
+ FILEFLAGS 1
+#else
+ FILEFLAGS 0
+#endif
+ FILEOS VOS__WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE 0x0L
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "CompanyName", "The cURL library, http://curl.haxx.se/\0"
+ VALUE "FileDescription", "libcurl Shared Library\0"
+ VALUE "FileVersion", LIBCURL_VERSION "\0"
+ VALUE "InternalName", "libcurl\0"
+ VALUE "OriginalFilename", "libcurl.dll\0"
+ VALUE "ProductName", "The cURL library\0"
+ VALUE "ProductVersion", LIBCURL_VERSION "\0"
+ VALUE "LegalCopyright", " " LIBCURL_COPYRIGHT "\0"
+ VALUE "License", "http://curl.haxx.se/docs/copyright.html\0"
+ END
+ END
+
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/libs/libcurl/src/llist.c b/libs/libcurl/src/llist.c
new file mode 100644
index 0000000000..40bb628379
--- /dev/null
+++ b/libs/libcurl/src/llist.c
@@ -0,0 +1,212 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "llist.h"
+#include "curl_memory.h"
+
+/* this must be the last include file */
+#include "memdebug.h"
+
+/*
+ * @unittest: 1300
+ */
+static void
+llist_init(struct curl_llist *l, curl_llist_dtor dtor)
+{
+ l->size = 0;
+ l->dtor = dtor;
+ l->head = NULL;
+ l->tail = NULL;
+}
+
+struct curl_llist *
+Curl_llist_alloc(curl_llist_dtor dtor)
+{
+ struct curl_llist *list;
+
+ list = malloc(sizeof(struct curl_llist));
+ if(!list)
+ return NULL;
+
+ llist_init(list, dtor);
+
+ return list;
+}
+
+/*
+ * Curl_llist_insert_next()
+ *
+ * Inserts a new list element after the given one 'e'. If the given existing
+ * entry is NULL and the list already has elements, the new one will be
+ * inserted first in the list.
+ *
+ * Returns: 1 on success and 0 on failure.
+ *
+ * @unittest: 1300
+ */
+int
+Curl_llist_insert_next(struct curl_llist *list, struct curl_llist_element *e,
+ const void *p)
+{
+ struct curl_llist_element *ne = malloc(sizeof(struct curl_llist_element));
+ if(!ne)
+ return 0;
+
+ ne->ptr = (void *) p;
+ if(list->size == 0) {
+ list->head = ne;
+ list->head->prev = NULL;
+ list->head->next = NULL;
+ list->tail = ne;
+ }
+ else {
+ /* if 'e' is NULL here, we insert the new element first in the list */
+ ne->next = e?e->next:list->head;
+ ne->prev = e;
+ if(!e) {
+ list->head->prev = ne;
+ list->head = ne;
+ }
+ else if(e->next) {
+ e->next->prev = ne;
+ }
+ else {
+ list->tail = ne;
+ }
+ if(e)
+ e->next = ne;
+ }
+
+ ++list->size;
+
+ return 1;
+}
+
+/*
+ * @unittest: 1300
+ */
+int
+Curl_llist_remove(struct curl_llist *list, struct curl_llist_element *e,
+ void *user)
+{
+ if(e == NULL || list->size == 0)
+ return 1;
+
+ if(e == list->head) {
+ list->head = e->next;
+
+ if(list->head == NULL)
+ list->tail = NULL;
+ else
+ e->next->prev = NULL;
+ }
+ else {
+ e->prev->next = e->next;
+ if(!e->next)
+ list->tail = e->prev;
+ else
+ e->next->prev = e->prev;
+ }
+
+ list->dtor(user, e->ptr);
+
+ e->ptr = NULL;
+ e->prev = NULL;
+ e->next = NULL;
+
+ free(e);
+ --list->size;
+
+ return 1;
+}
+
+void
+Curl_llist_destroy(struct curl_llist *list, void *user)
+{
+ if(list) {
+ while(list->size > 0)
+ Curl_llist_remove(list, list->tail, user);
+
+ free(list);
+ }
+}
+
+size_t
+Curl_llist_count(struct curl_llist *list)
+{
+ return list->size;
+}
+
+/*
+ * @unittest: 1300
+ */
+int Curl_llist_move(struct curl_llist *list, struct curl_llist_element *e,
+ struct curl_llist *to_list,
+ struct curl_llist_element *to_e)
+{
+ /* Remove element from list */
+ if(e == NULL || list->size == 0)
+ return 0;
+
+ if(e == list->head) {
+ list->head = e->next;
+
+ if(list->head == NULL)
+ list->tail = NULL;
+ else
+ e->next->prev = NULL;
+ }
+ else {
+ e->prev->next = e->next;
+ if(!e->next)
+ list->tail = e->prev;
+ else
+ e->next->prev = e->prev;
+ }
+
+ --list->size;
+
+ /* Add element to to_list after to_e */
+ if(to_list->size == 0) {
+ to_list->head = e;
+ to_list->head->prev = NULL;
+ to_list->head->next = NULL;
+ to_list->tail = e;
+ }
+ else {
+ e->next = to_e->next;
+ e->prev = to_e;
+ if(to_e->next) {
+ to_e->next->prev = e;
+ }
+ else {
+ to_list->tail = e;
+ }
+ to_e->next = e;
+ }
+
+ ++to_list->size;
+
+ return 1;
+}
diff --git a/libs/libcurl/src/llist.h b/libs/libcurl/src/llist.h
new file mode 100644
index 0000000000..27ddb719a5
--- /dev/null
+++ b/libs/libcurl/src/llist.h
@@ -0,0 +1,57 @@
+#ifndef HEADER_CURL_LLIST_H
+#define HEADER_CURL_LLIST_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stddef.h>
+
+typedef void (*curl_llist_dtor)(void *, void *);
+
+struct curl_llist_element {
+ void *ptr;
+
+ struct curl_llist_element *prev;
+ struct curl_llist_element *next;
+};
+
+struct curl_llist {
+ struct curl_llist_element *head;
+ struct curl_llist_element *tail;
+
+ curl_llist_dtor dtor;
+
+ size_t size;
+};
+
+struct curl_llist *Curl_llist_alloc(curl_llist_dtor);
+int Curl_llist_insert_next(struct curl_llist *, struct curl_llist_element *,
+ const void *);
+int Curl_llist_remove(struct curl_llist *, struct curl_llist_element *,
+ void *);
+size_t Curl_llist_count(struct curl_llist *);
+void Curl_llist_destroy(struct curl_llist *, void *);
+int Curl_llist_move(struct curl_llist *, struct curl_llist_element *,
+ struct curl_llist *, struct curl_llist_element *);
+
+#endif /* HEADER_CURL_LLIST_H */
+
diff --git a/libs/libcurl/src/md4.c b/libs/libcurl/src/md4.c
new file mode 100644
index 0000000000..6930e021af
--- /dev/null
+++ b/libs/libcurl/src/md4.c
@@ -0,0 +1,282 @@
+/*-
+ Copyright (C) 1990-2, RSA Data Security, Inc. All rights reserved.
+
+ License to copy and use this software is granted provided that it
+ is identified as the "RSA Data Security, Inc. MD4 Message-Digest
+ Algorithm" in all material mentioning or referencing this software
+ or this function.
+
+ License is also granted to make and use derivative works provided
+ that such works are identified as "derived from the RSA Data
+ Security, Inc. MD4 Message-Digest Algorithm" in all material
+ mentioning or referencing the derived work.
+
+ RSA Data Security, Inc. makes no representations concerning either
+ the merchantability of this software or the suitability of this
+ software for any particular purpose. It is provided "as is"
+ without express or implied warranty of any kind.
+
+ These notices must be retained in any copies of any part of this
+ documentation and/or software.
+ */
+
+#include "curl_setup.h"
+
+/* NSS crypto library does not provide the MD4 hash algorithm, so that we have
+ * a local implementation of it */
+#ifdef USE_NSS
+
+#include "curl_md4.h"
+#include "warnless.h"
+
+typedef unsigned int UINT4;
+
+typedef struct MD4Context {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+} MD4_CTX;
+
+/* Constants for MD4Transform routine.
+ */
+#define S11 3
+#define S12 7
+#define S13 11
+#define S14 19
+#define S21 3
+#define S22 5
+#define S23 9
+#define S24 13
+#define S31 3
+#define S32 9
+#define S33 11
+#define S34 15
+
+static void MD4Transform(UINT4 [4], const unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, const unsigned char *, unsigned int);
+
+static unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G and H are basic MD4 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG and HH are transformations for rounds 1, 2 and 3 */
+/* Rotation is separate from addition to prevent recomputation */
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)0x5a827999; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)0x6ed9eba1; \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ }
+
+/* MD4 initialization. Begins an MD4 operation, writing a new context.
+ */
+static void MD4Init(MD4_CTX *context)
+{
+ context->count[0] = context->count[1] = 0;
+
+ /* Load magic initialization constants.
+ */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD4 block update operation. Continues an MD4 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+static void MD4Update(MD4_CTX *context, const unsigned char *input,
+ unsigned int inputLen)
+{
+ unsigned int i, bufindex, partLen;
+
+ /* Compute number of bytes mod 64 */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
+ /* Update number of bits */
+ if((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - bufindex;
+ /* Transform as many times as possible.
+ */
+ if(inputLen >= partLen) {
+ memcpy(&context->buffer[bufindex], input, partLen);
+ MD4Transform (context->state, context->buffer);
+
+ for(i = partLen; i + 63 < inputLen; i += 64)
+ MD4Transform (context->state, &input[i]);
+
+ bufindex = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[bufindex], &input[i], inputLen-i);
+}
+
+/* MD4 padding. */
+static void MD4Pad(MD4_CTX *context)
+{
+ unsigned char bits[8];
+ unsigned int bufindex, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64.
+ */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (bufindex < 56) ? (56 - bufindex) : (120 - bufindex);
+ MD4Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD4Update (context, bits, 8);
+}
+
+/* MD4 finalization. Ends an MD4 message-digest operation, writing the
+ the message digest and zeroizing the context.
+ */
+static void MD4Final (unsigned char digest[16], MD4_CTX *context)
+{
+ /* Do padding */
+ MD4Pad (context);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information.
+ */
+ memset(context, 0, sizeof(*context));
+}
+
+/* MD4 basic transformation. Transforms state based on block.
+ */
+static void MD4Transform (UINT4 state[4], const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11); /* 1 */
+ FF (d, a, b, c, x[ 1], S12); /* 2 */
+ FF (c, d, a, b, x[ 2], S13); /* 3 */
+ FF (b, c, d, a, x[ 3], S14); /* 4 */
+ FF (a, b, c, d, x[ 4], S11); /* 5 */
+ FF (d, a, b, c, x[ 5], S12); /* 6 */
+ FF (c, d, a, b, x[ 6], S13); /* 7 */
+ FF (b, c, d, a, x[ 7], S14); /* 8 */
+ FF (a, b, c, d, x[ 8], S11); /* 9 */
+ FF (d, a, b, c, x[ 9], S12); /* 10 */
+ FF (c, d, a, b, x[10], S13); /* 11 */
+ FF (b, c, d, a, x[11], S14); /* 12 */
+ FF (a, b, c, d, x[12], S11); /* 13 */
+ FF (d, a, b, c, x[13], S12); /* 14 */
+ FF (c, d, a, b, x[14], S13); /* 15 */
+ FF (b, c, d, a, x[15], S14); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 0], S21); /* 17 */
+ GG (d, a, b, c, x[ 4], S22); /* 18 */
+ GG (c, d, a, b, x[ 8], S23); /* 19 */
+ GG (b, c, d, a, x[12], S24); /* 20 */
+ GG (a, b, c, d, x[ 1], S21); /* 21 */
+ GG (d, a, b, c, x[ 5], S22); /* 22 */
+ GG (c, d, a, b, x[ 9], S23); /* 23 */
+ GG (b, c, d, a, x[13], S24); /* 24 */
+ GG (a, b, c, d, x[ 2], S21); /* 25 */
+ GG (d, a, b, c, x[ 6], S22); /* 26 */
+ GG (c, d, a, b, x[10], S23); /* 27 */
+ GG (b, c, d, a, x[14], S24); /* 28 */
+ GG (a, b, c, d, x[ 3], S21); /* 29 */
+ GG (d, a, b, c, x[ 7], S22); /* 30 */
+ GG (c, d, a, b, x[11], S23); /* 31 */
+ GG (b, c, d, a, x[15], S24); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 0], S31); /* 33 */
+ HH (d, a, b, c, x[ 8], S32); /* 34 */
+ HH (c, d, a, b, x[ 4], S33); /* 35 */
+ HH (b, c, d, a, x[12], S34); /* 36 */
+ HH (a, b, c, d, x[ 2], S31); /* 37 */
+ HH (d, a, b, c, x[10], S32); /* 38 */
+ HH (c, d, a, b, x[ 6], S33); /* 39 */
+ HH (b, c, d, a, x[14], S34); /* 40 */
+ HH (a, b, c, d, x[ 1], S31); /* 41 */
+ HH (d, a, b, c, x[ 9], S32); /* 42 */
+ HH (c, d, a, b, x[ 5], S33); /* 43 */
+ HH (b, c, d, a, x[13], S34); /* 44 */
+ HH (a, b, c, d, x[ 3], S31); /* 45 */
+ HH (d, a, b, c, x[11], S32); /* 46 */
+ HH (c, d, a, b, x[ 7], S33); /* 47 */
+ HH (b, c, d, a, x[15], S34); /* 48 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information.
+ */
+ memset(x, 0, sizeof(x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode(unsigned char *output, UINT4 *input, unsigned int len)
+{
+ unsigned int i, j;
+
+ for(i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+ */
+static void Decode (UINT4 *output, const unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for(i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+void Curl_md4it(unsigned char *output, const unsigned char *input, size_t len)
+{
+ MD4_CTX ctx;
+ MD4Init(&ctx);
+ MD4Update(&ctx, input, curlx_uztoui(len));
+ MD4Final(output, &ctx);
+}
+#endif /* USE_NSS */
diff --git a/libs/libcurl/src/md5.c b/libs/libcurl/src/md5.c
new file mode 100644
index 0000000000..d8344dbe43
--- /dev/null
+++ b/libs/libcurl/src/md5.c
@@ -0,0 +1,541 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+
+#include "curl_md5.h"
+#include "curl_hmac.h"
+#include "warnless.h"
+
+#include "curl_memory.h"
+
+#if defined(USE_GNUTLS_NETTLE)
+
+#include <nettle/md5.h>
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef struct md5_ctx MD5_CTX;
+
+static void MD5_Init(MD5_CTX * ctx)
+{
+ md5_init(ctx);
+}
+
+static void MD5_Update(MD5_CTX * ctx,
+ const unsigned char * input,
+ unsigned int inputLen)
+{
+ md5_update(ctx, inputLen, input);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+{
+ md5_digest(ctx, 16, digest);
+}
+
+#elif defined(USE_GNUTLS)
+
+#include <gcrypt.h>
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef gcry_md_hd_t MD5_CTX;
+
+static void MD5_Init(MD5_CTX * ctx)
+{
+ gcry_md_open(ctx, GCRY_MD_MD5, 0);
+}
+
+static void MD5_Update(MD5_CTX * ctx,
+ const unsigned char * input,
+ unsigned int inputLen)
+{
+ gcry_md_write(*ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX * ctx)
+{
+ memcpy(digest, gcry_md_read(*ctx, 0), 16);
+ gcry_md_close(*ctx);
+}
+
+#elif defined(USE_SSLEAY)
+/* When OpenSSL is available we use the MD5-function from OpenSSL */
+
+# ifdef USE_OPENSSL
+# include <openssl/md5.h>
+# else
+# include <md5.h>
+# endif
+
+#elif (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && \
+ (__MAC_OS_X_VERSION_MAX_ALLOWED >= 1040)) || \
+ (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && \
+ (__IPHONE_OS_VERSION_MAX_ALLOWED >= 20000))
+
+/* For Apple operating systems: CommonCrypto has the functions we need.
+ These functions are available on Tiger and later, as well as iOS 2.0
+ and later. If you're building for an older cat, well, sorry.
+
+ Declaring the functions as static like this seems to be a bit more
+ reliable than defining COMMON_DIGEST_FOR_OPENSSL on older cats. */
+# include <CommonCrypto/CommonDigest.h>
+# define MD5_CTX CC_MD5_CTX
+
+static void MD5_Init(MD5_CTX *ctx)
+{
+ CC_MD5_Init(ctx);
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CC_MD5_Update(ctx, input, inputLen);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ CC_MD5_Final(digest, ctx);
+}
+
+#elif defined(_WIN32)
+
+#include <wincrypt.h>
+
+typedef struct {
+ HCRYPTPROV hCryptProv;
+ HCRYPTHASH hHash;
+} MD5_CTX;
+
+static void MD5_Init(MD5_CTX *ctx)
+{
+ if(CryptAcquireContext(&ctx->hCryptProv, NULL, NULL,
+ PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) {
+ CryptCreateHash(ctx->hCryptProv, CALG_MD5, 0, 0, &ctx->hHash);
+ }
+}
+
+static void MD5_Update(MD5_CTX *ctx,
+ const unsigned char *input,
+ unsigned int inputLen)
+{
+ CryptHashData(ctx->hHash, (unsigned char *)input, inputLen, 0);
+}
+
+static void MD5_Final(unsigned char digest[16], MD5_CTX *ctx)
+{
+ unsigned long length;
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, NULL, &length, 0);
+ if(length == 16)
+ CryptGetHashParam(ctx->hHash, HP_HASHVAL, digest, &length, 0);
+ if(ctx->hHash)
+ CryptDestroyHash(ctx->hHash);
+ if(ctx->hCryptProv)
+ CryptReleaseContext(ctx->hCryptProv, 0);
+}
+
+#else
+/* When no other crypto library is available we use this code segment */
+
+/* Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+rights reserved.
+
+License to copy and use this software is granted provided that it
+is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+Algorithm" in all material mentioning or referencing this software
+or this function.
+
+License is also granted to make and use derivative works provided
+that such works are identified as "derived from the RSA Data
+Security, Inc. MD5 Message-Digest Algorithm" in all material
+mentioning or referencing the derived work.
+
+RSA Data Security, Inc. makes no representations concerning either
+the merchantability of this software or the suitability of this
+software for any particular purpose. It is provided "as is"
+without express or implied warranty of any kind.
+
+These notices must be retained in any copies of any part of this
+documentation and/or software.
+ */
+
+/* UINT4 defines a four byte word */
+typedef unsigned int UINT4;
+
+/* MD5 context. */
+struct md5_ctx {
+ UINT4 state[4]; /* state (ABCD) */
+ UINT4 count[2]; /* number of bits, modulo 2^64 (lsb first) */
+ unsigned char buffer[64]; /* input buffer */
+};
+
+typedef struct md5_ctx MD5_CTX;
+
+static void MD5_Init(struct md5_ctx *);
+static void MD5_Update(struct md5_ctx *, const unsigned char *, unsigned int);
+static void MD5_Final(unsigned char [16], struct md5_ctx *);
+
+/* Constants for MD5Transform routine.
+ */
+
+#define S11 7
+#define S12 12
+#define S13 17
+#define S14 22
+#define S21 5
+#define S22 9
+#define S23 14
+#define S24 20
+#define S31 4
+#define S32 11
+#define S33 16
+#define S34 23
+#define S41 6
+#define S42 10
+#define S43 15
+#define S44 21
+
+static void MD5Transform(UINT4 [4], const unsigned char [64]);
+static void Encode(unsigned char *, UINT4 *, unsigned int);
+static void Decode(UINT4 *, const unsigned char *, unsigned int);
+
+static const unsigned char PADDING[64] = {
+ 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+/* F, G, H and I are basic MD5 functions.
+ */
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+#define I(x, y, z) ((y) ^ ((x) | (~z)))
+
+/* ROTATE_LEFT rotates x left n bits.
+ */
+#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32-(n))))
+
+/* FF, GG, HH, and II transformations for rounds 1, 2, 3, and 4.
+Rotation is separate from addition to prevent recomputation.
+ */
+#define FF(a, b, c, d, x, s, ac) { \
+ (a) += F ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define GG(a, b, c, d, x, s, ac) { \
+ (a) += G ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define HH(a, b, c, d, x, s, ac) { \
+ (a) += H ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+#define II(a, b, c, d, x, s, ac) { \
+ (a) += I ((b), (c), (d)) + (x) + (UINT4)(ac); \
+ (a) = ROTATE_LEFT ((a), (s)); \
+ (a) += (b); \
+ }
+
+/* MD5 initialization. Begins an MD5 operation, writing a new context.
+ */
+static void MD5_Init(struct md5_ctx *context)
+{
+ context->count[0] = context->count[1] = 0;
+ /* Load magic initialization constants. */
+ context->state[0] = 0x67452301;
+ context->state[1] = 0xefcdab89;
+ context->state[2] = 0x98badcfe;
+ context->state[3] = 0x10325476;
+}
+
+/* MD5 block update operation. Continues an MD5 message-digest
+ operation, processing another message block, and updating the
+ context.
+ */
+static void MD5_Update (struct md5_ctx *context, /* context */
+ const unsigned char *input, /* input block */
+ unsigned int inputLen) /* length of input block */
+{
+ unsigned int i, bufindex, partLen;
+
+ /* Compute number of bytes mod 64 */
+ bufindex = (unsigned int)((context->count[0] >> 3) & 0x3F);
+
+ /* Update number of bits */
+ if((context->count[0] += ((UINT4)inputLen << 3))
+ < ((UINT4)inputLen << 3))
+ context->count[1]++;
+ context->count[1] += ((UINT4)inputLen >> 29);
+
+ partLen = 64 - bufindex;
+
+ /* Transform as many times as possible. */
+ if(inputLen >= partLen) {
+ memcpy(&context->buffer[bufindex], input, partLen);
+ MD5Transform(context->state, context->buffer);
+
+ for(i = partLen; i + 63 < inputLen; i += 64)
+ MD5Transform(context->state, &input[i]);
+
+ bufindex = 0;
+ }
+ else
+ i = 0;
+
+ /* Buffer remaining input */
+ memcpy(&context->buffer[bufindex], &input[i], inputLen-i);
+}
+
+/* MD5 finalization. Ends an MD5 message-digest operation, writing the
+ the message digest and zeroizing the context.
+*/
+static void MD5_Final(unsigned char digest[16], /* message digest */
+ struct md5_ctx *context) /* context */
+{
+ unsigned char bits[8];
+ unsigned int count, padLen;
+
+ /* Save number of bits */
+ Encode (bits, context->count, 8);
+
+ /* Pad out to 56 mod 64. */
+ count = (unsigned int)((context->count[0] >> 3) & 0x3f);
+ padLen = (count < 56) ? (56 - count) : (120 - count);
+ MD5_Update (context, PADDING, padLen);
+
+ /* Append length (before padding) */
+ MD5_Update (context, bits, 8);
+
+ /* Store state in digest */
+ Encode (digest, context->state, 16);
+
+ /* Zeroize sensitive information. */
+ memset ((void *)context, 0, sizeof (*context));
+}
+
+/* MD5 basic transformation. Transforms state based on block. */
+static void MD5Transform(UINT4 state[4],
+ const unsigned char block[64])
+{
+ UINT4 a = state[0], b = state[1], c = state[2], d = state[3], x[16];
+
+ Decode (x, block, 64);
+
+ /* Round 1 */
+ FF (a, b, c, d, x[ 0], S11, 0xd76aa478); /* 1 */
+ FF (d, a, b, c, x[ 1], S12, 0xe8c7b756); /* 2 */
+ FF (c, d, a, b, x[ 2], S13, 0x242070db); /* 3 */
+ FF (b, c, d, a, x[ 3], S14, 0xc1bdceee); /* 4 */
+ FF (a, b, c, d, x[ 4], S11, 0xf57c0faf); /* 5 */
+ FF (d, a, b, c, x[ 5], S12, 0x4787c62a); /* 6 */
+ FF (c, d, a, b, x[ 6], S13, 0xa8304613); /* 7 */
+ FF (b, c, d, a, x[ 7], S14, 0xfd469501); /* 8 */
+ FF (a, b, c, d, x[ 8], S11, 0x698098d8); /* 9 */
+ FF (d, a, b, c, x[ 9], S12, 0x8b44f7af); /* 10 */
+ FF (c, d, a, b, x[10], S13, 0xffff5bb1); /* 11 */
+ FF (b, c, d, a, x[11], S14, 0x895cd7be); /* 12 */
+ FF (a, b, c, d, x[12], S11, 0x6b901122); /* 13 */
+ FF (d, a, b, c, x[13], S12, 0xfd987193); /* 14 */
+ FF (c, d, a, b, x[14], S13, 0xa679438e); /* 15 */
+ FF (b, c, d, a, x[15], S14, 0x49b40821); /* 16 */
+
+ /* Round 2 */
+ GG (a, b, c, d, x[ 1], S21, 0xf61e2562); /* 17 */
+ GG (d, a, b, c, x[ 6], S22, 0xc040b340); /* 18 */
+ GG (c, d, a, b, x[11], S23, 0x265e5a51); /* 19 */
+ GG (b, c, d, a, x[ 0], S24, 0xe9b6c7aa); /* 20 */
+ GG (a, b, c, d, x[ 5], S21, 0xd62f105d); /* 21 */
+ GG (d, a, b, c, x[10], S22, 0x2441453); /* 22 */
+ GG (c, d, a, b, x[15], S23, 0xd8a1e681); /* 23 */
+ GG (b, c, d, a, x[ 4], S24, 0xe7d3fbc8); /* 24 */
+ GG (a, b, c, d, x[ 9], S21, 0x21e1cde6); /* 25 */
+ GG (d, a, b, c, x[14], S22, 0xc33707d6); /* 26 */
+ GG (c, d, a, b, x[ 3], S23, 0xf4d50d87); /* 27 */
+ GG (b, c, d, a, x[ 8], S24, 0x455a14ed); /* 28 */
+ GG (a, b, c, d, x[13], S21, 0xa9e3e905); /* 29 */
+ GG (d, a, b, c, x[ 2], S22, 0xfcefa3f8); /* 30 */
+ GG (c, d, a, b, x[ 7], S23, 0x676f02d9); /* 31 */
+ GG (b, c, d, a, x[12], S24, 0x8d2a4c8a); /* 32 */
+
+ /* Round 3 */
+ HH (a, b, c, d, x[ 5], S31, 0xfffa3942); /* 33 */
+ HH (d, a, b, c, x[ 8], S32, 0x8771f681); /* 34 */
+ HH (c, d, a, b, x[11], S33, 0x6d9d6122); /* 35 */
+ HH (b, c, d, a, x[14], S34, 0xfde5380c); /* 36 */
+ HH (a, b, c, d, x[ 1], S31, 0xa4beea44); /* 37 */
+ HH (d, a, b, c, x[ 4], S32, 0x4bdecfa9); /* 38 */
+ HH (c, d, a, b, x[ 7], S33, 0xf6bb4b60); /* 39 */
+ HH (b, c, d, a, x[10], S34, 0xbebfbc70); /* 40 */
+ HH (a, b, c, d, x[13], S31, 0x289b7ec6); /* 41 */
+ HH (d, a, b, c, x[ 0], S32, 0xeaa127fa); /* 42 */
+ HH (c, d, a, b, x[ 3], S33, 0xd4ef3085); /* 43 */
+ HH (b, c, d, a, x[ 6], S34, 0x4881d05); /* 44 */
+ HH (a, b, c, d, x[ 9], S31, 0xd9d4d039); /* 45 */
+ HH (d, a, b, c, x[12], S32, 0xe6db99e5); /* 46 */
+ HH (c, d, a, b, x[15], S33, 0x1fa27cf8); /* 47 */
+ HH (b, c, d, a, x[ 2], S34, 0xc4ac5665); /* 48 */
+
+ /* Round 4 */
+ II (a, b, c, d, x[ 0], S41, 0xf4292244); /* 49 */
+ II (d, a, b, c, x[ 7], S42, 0x432aff97); /* 50 */
+ II (c, d, a, b, x[14], S43, 0xab9423a7); /* 51 */
+ II (b, c, d, a, x[ 5], S44, 0xfc93a039); /* 52 */
+ II (a, b, c, d, x[12], S41, 0x655b59c3); /* 53 */
+ II (d, a, b, c, x[ 3], S42, 0x8f0ccc92); /* 54 */
+ II (c, d, a, b, x[10], S43, 0xffeff47d); /* 55 */
+ II (b, c, d, a, x[ 1], S44, 0x85845dd1); /* 56 */
+ II (a, b, c, d, x[ 8], S41, 0x6fa87e4f); /* 57 */
+ II (d, a, b, c, x[15], S42, 0xfe2ce6e0); /* 58 */
+ II (c, d, a, b, x[ 6], S43, 0xa3014314); /* 59 */
+ II (b, c, d, a, x[13], S44, 0x4e0811a1); /* 60 */
+ II (a, b, c, d, x[ 4], S41, 0xf7537e82); /* 61 */
+ II (d, a, b, c, x[11], S42, 0xbd3af235); /* 62 */
+ II (c, d, a, b, x[ 2], S43, 0x2ad7d2bb); /* 63 */
+ II (b, c, d, a, x[ 9], S44, 0xeb86d391); /* 64 */
+
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+
+ /* Zeroize sensitive information. */
+ memset((void *)x, 0, sizeof (x));
+}
+
+/* Encodes input (UINT4) into output (unsigned char). Assumes len is
+ a multiple of 4.
+ */
+static void Encode (unsigned char *output,
+ UINT4 *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for(i = 0, j = 0; j < len; i++, j += 4) {
+ output[j] = (unsigned char)(input[i] & 0xff);
+ output[j+1] = (unsigned char)((input[i] >> 8) & 0xff);
+ output[j+2] = (unsigned char)((input[i] >> 16) & 0xff);
+ output[j+3] = (unsigned char)((input[i] >> 24) & 0xff);
+ }
+}
+
+/* Decodes input (unsigned char) into output (UINT4). Assumes len is
+ a multiple of 4.
+*/
+static void Decode (UINT4 *output,
+ const unsigned char *input,
+ unsigned int len)
+{
+ unsigned int i, j;
+
+ for(i = 0, j = 0; j < len; i++, j += 4)
+ output[i] = ((UINT4)input[j]) | (((UINT4)input[j+1]) << 8) |
+ (((UINT4)input[j+2]) << 16) | (((UINT4)input[j+3]) << 24);
+}
+
+#endif /* CRYPTO LIBS */
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+const HMAC_params Curl_HMAC_MD5[] = {
+ {
+ (HMAC_hinit_func) MD5_Init, /* Hash initialization function. */
+ (HMAC_hupdate_func) MD5_Update, /* Hash update function. */
+ (HMAC_hfinal_func) MD5_Final, /* Hash computation end function. */
+ sizeof(MD5_CTX), /* Size of hash context structure. */
+ 64, /* Maximum key length. */
+ 16 /* Result size. */
+ }
+};
+
+const MD5_params Curl_DIGEST_MD5[] = {
+ {
+ (Curl_MD5_init_func) MD5_Init, /* Digest initialization function */
+ (Curl_MD5_update_func) MD5_Update, /* Digest update function */
+ (Curl_MD5_final_func) MD5_Final, /* Digest computation end function */
+ sizeof(MD5_CTX), /* Size of digest context struct */
+ 16 /* Result size */
+ }
+};
+
+void Curl_md5it(unsigned char *outbuffer, /* 16 bytes */
+ const unsigned char *input)
+{
+ MD5_CTX ctx;
+ MD5_Init(&ctx);
+ MD5_Update(&ctx, input, curlx_uztoui(strlen((char *)input)));
+ MD5_Final(outbuffer, &ctx);
+}
+
+MD5_context *Curl_MD5_init(const MD5_params *md5params)
+{
+ MD5_context *ctxt;
+
+ /* Create MD5 context */
+ ctxt = malloc(sizeof *ctxt);
+
+ if(!ctxt)
+ return ctxt;
+
+ ctxt->md5_hashctx = malloc(md5params->md5_ctxtsize);
+
+ if(!ctxt->md5_hashctx) {
+ free(ctxt);
+ return NULL;
+ }
+
+ ctxt->md5_hash = md5params;
+
+ (*md5params->md5_init_func)(ctxt->md5_hashctx);
+
+ return ctxt;
+}
+
+int Curl_MD5_update(MD5_context *context,
+ const unsigned char *data,
+ unsigned int len)
+{
+ (*context->md5_hash->md5_update_func)(context->md5_hashctx, data, len);
+
+ return 0;
+}
+
+int Curl_MD5_final(MD5_context *context, unsigned char *result)
+{
+ (*context->md5_hash->md5_final_func)(result, context->md5_hashctx);
+
+ free(context->md5_hashctx);
+ free(context);
+
+ return 0;
+}
+
+#endif /* CURL_DISABLE_CRYPTO_AUTH */
diff --git a/libs/libcurl/src/memdebug.c b/libs/libcurl/src/memdebug.c
new file mode 100644
index 0000000000..7d68af874c
--- /dev/null
+++ b/libs/libcurl/src/memdebug.c
@@ -0,0 +1,489 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 CURLDEBUG
+
+#include <curl/curl.h>
+
+#define _MPRINTF_REPLACE
+#include <curl/mprintf.h>
+#include "urldata.h"
+
+#define MEMDEBUG_NODEFINES /* don't redefine the standard functions */
+#include "curl_memory.h"
+#include "memdebug.h"
+
+#ifndef HAVE_ASSERT_H
+# define assert(x) Curl_nop_stmt
+#endif
+
+/*
+ * Until 2011-08-17 libcurl's Memory Tracking feature also performed
+ * automatic malloc and free filling operations using 0xA5 and 0x13
+ * values. Our own preinitialization of dynamically allocated memory
+ * might be useful when not using third party memory debuggers, but
+ * on the other hand this would fool memory debuggers into thinking
+ * that all dynamically allocated memory is properly initialized.
+ *
+ * As a default setting, libcurl's Memory Tracking feature no longer
+ * performs preinitialization of dynamically allocated memory on its
+ * own. If you know what you are doing, and really want to retain old
+ * behavior, you can achieve this compiling with preprocessor symbols
+ * CURL_MT_MALLOC_FILL and CURL_MT_FREE_FILL defined with appropriate
+ * values.
+ */
+
+#ifdef CURL_MT_MALLOC_FILL
+# if (CURL_MT_MALLOC_FILL < 0) || (CURL_MT_MALLOC_FILL > 0xff)
+# error "invalid CURL_MT_MALLOC_FILL or out of range"
+# endif
+#endif
+
+#ifdef CURL_MT_FREE_FILL
+# if (CURL_MT_FREE_FILL < 0) || (CURL_MT_FREE_FILL > 0xff)
+# error "invalid CURL_MT_FREE_FILL or out of range"
+# endif
+#endif
+
+#if defined(CURL_MT_MALLOC_FILL) && defined(CURL_MT_FREE_FILL)
+# if (CURL_MT_MALLOC_FILL == CURL_MT_FREE_FILL)
+# error "CURL_MT_MALLOC_FILL same as CURL_MT_FREE_FILL"
+# endif
+#endif
+
+#ifdef CURL_MT_MALLOC_FILL
+# define mt_malloc_fill(buf,len) memset((buf), CURL_MT_MALLOC_FILL, (len))
+#else
+# define mt_malloc_fill(buf,len) Curl_nop_stmt
+#endif
+
+#ifdef CURL_MT_FREE_FILL
+# define mt_free_fill(buf,len) memset((buf), CURL_MT_FREE_FILL, (len))
+#else
+# define mt_free_fill(buf,len) Curl_nop_stmt
+#endif
+
+struct memdebug {
+ size_t size;
+ union {
+ curl_off_t o;
+ double d;
+ void * p;
+ } mem[1];
+ /* I'm hoping this is the thing with the strictest alignment
+ * requirements. That also means we waste some space :-( */
+};
+
+/*
+ * Note that these debug functions are very simple and they are meant to
+ * remain so. For advanced analysis, record a log file and write perl scripts
+ * to analyze them!
+ *
+ * Don't use these with multithreaded test programs!
+ */
+
+#define logfile curl_debuglogfile
+FILE *curl_debuglogfile = NULL;
+static bool memlimit = FALSE; /* enable memory limit */
+static long memsize = 0; /* set number of mallocs allowed */
+
+/* this sets the log file name */
+void curl_memdebug(const char *logname)
+{
+ if(!logfile) {
+ if(logname && *logname)
+ logfile = fopen(logname, "w");
+ else
+ logfile = stderr;
+#ifdef MEMDEBUG_LOG_SYNC
+ /* Flush the log file after every line so the log isn't lost in a crash */
+ setvbuf(logfile, (char *)NULL, _IOLBF, 0);
+#endif
+ }
+}
+
+/* This function sets the number of malloc() calls that should return
+ successfully! */
+void curl_memlimit(long limit)
+{
+ if(!memlimit) {
+ memlimit = TRUE;
+ memsize = limit;
+ }
+}
+
+/* returns TRUE if this isn't allowed! */
+static bool countcheck(const char *func, int line, const char *source)
+{
+ /* if source is NULL, then the call is made internally and this check
+ should not be made */
+ if(memlimit && source) {
+ if(!memsize) {
+ if(source) {
+ /* log to file */
+ curl_memlog("LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ /* log to stderr also */
+ fprintf(stderr, "LIMIT %s:%d %s reached memlimit\n",
+ source, line, func);
+ }
+ SET_ERRNO(ENOMEM);
+ return TRUE; /* RETURN ERROR! */
+ }
+ else
+ memsize--; /* countdown */
+
+ /* log the countdown */
+ if(source)
+ curl_memlog("LIMIT %s:%d %ld ALLOCS left\n",
+ source, line, memsize);
+
+ }
+
+ return FALSE; /* allow this */
+}
+
+void *curl_domalloc(size_t wantedsize, int line, const char *source)
+{
+ struct memdebug *mem;
+ size_t size;
+
+ assert(wantedsize != 0);
+
+ if(countcheck("malloc", line, source))
+ return NULL;
+
+ /* alloc at least 64 bytes */
+ size = sizeof(struct memdebug)+wantedsize;
+
+ mem = (Curl_cmalloc)(size);
+ if(mem) {
+ /* fill memory with junk */
+ mt_malloc_fill(mem->mem, wantedsize);
+ mem->size = wantedsize;
+ }
+
+ if(source)
+ curl_memlog("MEM %s:%d malloc(%zu) = %p\n",
+ source, line, wantedsize,
+ mem ? (void *)mem->mem : (void *)0);
+
+ return (mem ? mem->mem : NULL);
+}
+
+void *curl_docalloc(size_t wanted_elements, size_t wanted_size,
+ int line, const char *source)
+{
+ struct memdebug *mem;
+ size_t size, user_size;
+
+ assert(wanted_elements != 0);
+ assert(wanted_size != 0);
+
+ if(countcheck("calloc", line, source))
+ return NULL;
+
+ /* alloc at least 64 bytes */
+ user_size = wanted_size * wanted_elements;
+ size = sizeof(struct memdebug) + user_size;
+
+ mem = (Curl_ccalloc)(1, size);
+ if(mem)
+ mem->size = user_size;
+
+ if(source)
+ curl_memlog("MEM %s:%d calloc(%zu,%zu) = %p\n",
+ source, line, wanted_elements, wanted_size,
+ mem ? (void *)mem->mem : (void *)0);
+
+ return (mem ? mem->mem : NULL);
+}
+
+char *curl_dostrdup(const char *str, int line, const char *source)
+{
+ char *mem;
+ size_t len;
+
+ assert(str != NULL);
+
+ if(countcheck("strdup", line, source))
+ return NULL;
+
+ len=strlen(str)+1;
+
+ mem=curl_domalloc(len, 0, NULL); /* NULL prevents logging */
+ if(mem)
+ memcpy(mem, str, len);
+
+ if(source)
+ curl_memlog("MEM %s:%d strdup(%p) (%zu) = %p\n",
+ source, line, (void *)str, len, (void *)mem);
+
+ return mem;
+}
+
+#if defined(WIN32) && defined(UNICODE)
+wchar_t *curl_dowcsdup(const wchar_t *str, int line, const char *source)
+{
+ wchar_t *mem;
+ size_t wsiz, bsiz;
+
+ assert(str != NULL);
+
+ if(countcheck("wcsdup", line, source))
+ return NULL;
+
+ wsiz = wcslen(str) + 1;
+ bsiz = wsiz * sizeof(wchar_t);
+
+ mem = curl_domalloc(bsiz, 0, NULL); /* NULL prevents logging */
+ if(mem)
+ memcpy(mem, str, bsiz);
+
+ if(source)
+ curl_memlog("MEM %s:%d wcsdup(%p) (%zu) = %p\n",
+ source, line, (void *)str, bsiz, (void *)mem);
+
+ return mem;
+}
+#endif
+
+/* We provide a realloc() that accepts a NULL as pointer, which then
+ performs a malloc(). In order to work with ares. */
+void *curl_dorealloc(void *ptr, size_t wantedsize,
+ int line, const char *source)
+{
+ struct memdebug *mem=NULL;
+
+ size_t size = sizeof(struct memdebug)+wantedsize;
+
+ assert(wantedsize != 0);
+
+ if(countcheck("realloc", line, source))
+ return NULL;
+
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:1684)
+ /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+ if(ptr)
+ mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+
+ mem = (Curl_crealloc)(mem, size);
+ if(source)
+ curl_memlog("MEM %s:%d realloc(%p, %zu) = %p\n",
+ source, line, (void *)ptr, wantedsize,
+ mem ? (void *)mem->mem : (void *)0);
+
+ if(mem) {
+ mem->size = wantedsize;
+ return mem->mem;
+ }
+
+ return NULL;
+}
+
+void curl_dofree(void *ptr, int line, const char *source)
+{
+ struct memdebug *mem;
+
+ assert(ptr != NULL);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:1684)
+ /* 1684: conversion from pointer to same-sized integral type */
+#endif
+
+ mem = (void *)((char *)ptr - offsetof(struct memdebug, mem));
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+
+ /* destroy */
+ mt_free_fill(mem->mem, mem->size);
+
+ /* free for real */
+ (Curl_cfree)(mem);
+
+ if(source)
+ curl_memlog("MEM %s:%d free(%p)\n", source, line, (void *)ptr);
+}
+
+curl_socket_t curl_socket(int domain, int type, int protocol,
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socket() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socket() = %ld\n" :
+ "FD %s:%d socket() = %zd\n" ;
+
+ curl_socket_t sockfd = socket(domain, type, protocol);
+
+ if(source && (sockfd != CURL_SOCKET_BAD))
+ curl_memlog(fmt, source, line, sockfd);
+
+ return sockfd;
+}
+
+#ifdef HAVE_SOCKETPAIR
+int curl_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d socketpair() = %d %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d socketpair() = %ld %ld\n" :
+ "FD %s:%d socketpair() = %zd %zd\n" ;
+
+ int res = socketpair(domain, type, protocol, socket_vector);
+
+ if(source && (0 == res))
+ curl_memlog(fmt, source, line, socket_vector[0], socket_vector[1]);
+
+ return res;
+}
+#endif
+
+curl_socket_t curl_accept(curl_socket_t s, void *saddr, void *saddrlen,
+ int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d accept() = %d\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d accept() = %ld\n" :
+ "FD %s:%d accept() = %zd\n" ;
+
+ struct sockaddr *addr = (struct sockaddr *)saddr;
+ curl_socklen_t *addrlen = (curl_socklen_t *)saddrlen;
+
+ curl_socket_t sockfd = accept(s, addr, addrlen);
+
+ if(source && (sockfd != CURL_SOCKET_BAD))
+ curl_memlog(fmt, source, line, sockfd);
+
+ return sockfd;
+}
+
+/* separate function to allow libcurl to mark a "faked" close */
+void curl_mark_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+ const char *fmt = (sizeof(curl_socket_t) == sizeof(int)) ?
+ "FD %s:%d sclose(%d)\n" :
+ (sizeof(curl_socket_t) == sizeof(long)) ?
+ "FD %s:%d sclose(%ld)\n" :
+ "FD %s:%d sclose(%zd)\n" ;
+
+ if(source)
+ curl_memlog(fmt, source, line, sockfd);
+}
+
+/* this is our own defined way to close sockets on *ALL* platforms */
+int curl_sclose(curl_socket_t sockfd, int line, const char *source)
+{
+ int res=sclose(sockfd);
+ curl_mark_sclose(sockfd, line, source);
+ return res;
+}
+
+FILE *curl_fopen(const char *file, const char *mode,
+ int line, const char *source)
+{
+ FILE *res=fopen(file, mode);
+
+ if(source)
+ curl_memlog("FILE %s:%d fopen(\"%s\",\"%s\") = %p\n",
+ source, line, file, mode, (void *)res);
+
+ return res;
+}
+
+#ifdef HAVE_FDOPEN
+FILE *curl_fdopen(int filedes, const char *mode,
+ int line, const char *source)
+{
+ FILE *res=fdopen(filedes, mode);
+
+ if(source)
+ curl_memlog("FILE %s:%d fdopen(\"%d\",\"%s\") = %p\n",
+ source, line, filedes, mode, (void *)res);
+
+ return res;
+}
+#endif
+
+int curl_fclose(FILE *file, int line, const char *source)
+{
+ int res;
+
+ assert(file != NULL);
+
+ res=fclose(file);
+
+ if(source)
+ curl_memlog("FILE %s:%d fclose(%p)\n",
+ source, line, (void *)file);
+
+ return res;
+}
+
+#define LOGLINE_BUFSIZE 1024
+
+/* this does the writting to the memory tracking log file */
+void curl_memlog(const char *format, ...)
+{
+ char *buf;
+ int nchars;
+ va_list ap;
+
+ if(!logfile)
+ return;
+
+ buf = (Curl_cmalloc)(LOGLINE_BUFSIZE);
+ if(!buf)
+ return;
+
+ va_start(ap, format);
+ nchars = vsnprintf(buf, LOGLINE_BUFSIZE, format, ap);
+ va_end(ap);
+
+ if(nchars > LOGLINE_BUFSIZE - 1)
+ nchars = LOGLINE_BUFSIZE - 1;
+
+ if(nchars > 0)
+ fwrite(buf, 1, nchars, logfile);
+
+ (Curl_cfree)(buf);
+}
+
+#endif /* CURLDEBUG */
diff --git a/libs/libcurl/src/memdebug.h b/libs/libcurl/src/memdebug.h
new file mode 100644
index 0000000000..bd565c8dcf
--- /dev/null
+++ b/libs/libcurl/src/memdebug.h
@@ -0,0 +1,176 @@
+#ifndef HEADER_CURL_MEMDEBUG_H
+#define HEADER_CURL_MEMDEBUG_H
+#ifdef CURLDEBUG
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#define CURL_MT_LOGFNAME_BUFSIZE 512
+
+#define logfile curl_debuglogfile
+
+extern FILE *logfile;
+
+/* memory functions */
+CURL_EXTERN void *curl_domalloc(size_t size, int line, const char *source);
+CURL_EXTERN void *curl_docalloc(size_t elements, size_t size, int line,
+ const char *source);
+CURL_EXTERN void *curl_dorealloc(void *ptr, size_t size, int line,
+ const char *source);
+CURL_EXTERN void curl_dofree(void *ptr, int line, const char *source);
+CURL_EXTERN char *curl_dostrdup(const char *str, int line, const char *source);
+#if defined(WIN32) && defined(UNICODE)
+CURL_EXTERN wchar_t *curl_dowcsdup(const wchar_t *str, int line,
+ const char *source);
+#endif
+
+CURL_EXTERN void curl_memdebug(const char *logname);
+CURL_EXTERN void curl_memlimit(long limit);
+CURL_EXTERN void curl_memlog(const char *format, ...);
+
+/* file descriptor manipulators */
+CURL_EXTERN curl_socket_t curl_socket(int domain, int type, int protocol,
+ int line , const char *source);
+CURL_EXTERN void curl_mark_sclose(curl_socket_t sockfd,
+ int line , const char *source);
+CURL_EXTERN int curl_sclose(curl_socket_t sockfd,
+ int line , const char *source);
+CURL_EXTERN curl_socket_t curl_accept(curl_socket_t s, void *a, void *alen,
+ int line, const char *source);
+#ifdef HAVE_SOCKETPAIR
+CURL_EXTERN int curl_socketpair(int domain, int type, int protocol,
+ curl_socket_t socket_vector[2],
+ int line , const char *source);
+#endif
+
+/* FILE functions */
+CURL_EXTERN FILE *curl_fopen(const char *file, const char *mode, int line,
+ const char *source);
+#ifdef HAVE_FDOPEN
+CURL_EXTERN FILE *curl_fdopen(int filedes, const char *mode, int line,
+ const char *source);
+#endif
+CURL_EXTERN int curl_fclose(FILE *file, int line, const char *source);
+
+#ifndef MEMDEBUG_NODEFINES
+
+/* Set this symbol on the command-line, recompile all lib-sources */
+#undef strdup
+#define strdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+#define malloc(size) curl_domalloc(size, __LINE__, __FILE__)
+#define calloc(nbelem,size) curl_docalloc(nbelem, size, __LINE__, __FILE__)
+#define realloc(ptr,size) curl_dorealloc(ptr, size, __LINE__, __FILE__)
+#define free(ptr) curl_dofree(ptr, __LINE__, __FILE__)
+
+#ifdef WIN32
+# ifdef UNICODE
+# undef wcsdup
+# define wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# undef _wcsdup
+# define _wcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# undef _tcsdup
+# define _tcsdup(ptr) curl_dowcsdup(ptr, __LINE__, __FILE__)
+# else
+# undef _tcsdup
+# define _tcsdup(ptr) curl_dostrdup(ptr, __LINE__, __FILE__)
+# endif
+#endif
+
+#define socket(domain,type,protocol)\
+ curl_socket(domain,type,protocol,__LINE__,__FILE__)
+#undef accept /* for those with accept as a macro */
+#define accept(sock,addr,len)\
+ curl_accept(sock,addr,len,__LINE__,__FILE__)
+#ifdef HAVE_SOCKETPAIR
+#define socketpair(domain,type,protocol,socket_vector)\
+ curl_socketpair(domain,type,protocol,socket_vector,__LINE__,__FILE__)
+#endif
+
+#ifdef HAVE_GETADDRINFO
+#if defined(getaddrinfo) && defined(__osf__)
+/* OSF/1 and Tru64 have getaddrinfo as a define already, so we cannot define
+ our macro as for other platforms. Instead, we redefine the new name they
+ define getaddrinfo to become! */
+#define ogetaddrinfo(host,serv,hint,res) \
+ curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#else
+#undef getaddrinfo
+#define getaddrinfo(host,serv,hint,res) \
+ curl_dogetaddrinfo(host,serv,hint,res,__LINE__,__FILE__)
+#endif
+#endif /* HAVE_GETADDRINFO */
+
+#ifdef HAVE_GETNAMEINFO
+#undef getnameinfo
+#define getnameinfo(sa,salen,host,hostlen,serv,servlen,flags) \
+ curl_dogetnameinfo(sa,salen,host,hostlen,serv,servlen,flags, __LINE__, \
+ __FILE__)
+#endif /* HAVE_GETNAMEINFO */
+
+#ifdef HAVE_FREEADDRINFO
+#undef freeaddrinfo
+#define freeaddrinfo(data) \
+ curl_dofreeaddrinfo(data,__LINE__,__FILE__)
+#endif /* HAVE_FREEADDRINFO */
+
+/* sclose is probably already defined, redefine it! */
+#undef sclose
+#define sclose(sockfd) curl_sclose(sockfd,__LINE__,__FILE__)
+
+#define fake_sclose(sockfd) curl_mark_sclose(sockfd,__LINE__,__FILE__)
+
+#undef fopen
+#define fopen(file,mode) curl_fopen(file,mode,__LINE__,__FILE__)
+#undef fdopen
+#define fdopen(file,mode) curl_fdopen(file,mode,__LINE__,__FILE__)
+#define fclose(file) curl_fclose(file,__LINE__,__FILE__)
+
+#endif /* MEMDEBUG_NODEFINES */
+
+#endif /* CURLDEBUG */
+
+/*
+** Following section applies even when CURLDEBUG is not defined.
+*/
+
+#ifndef fake_sclose
+#define fake_sclose(x) Curl_nop_stmt
+#endif
+
+/*
+ * Curl_safefree defined as a macro to allow MemoryTracking feature
+ * to log free() calls at same location where Curl_safefree is used.
+ * This macro also assigns NULL to given pointer when free'd.
+ */
+
+#define Curl_safefree(ptr) \
+ do {if((ptr)) {free((ptr)); (ptr) = NULL;}} WHILE_FALSE
+
+#endif /* HEADER_CURL_MEMDEBUG_H */
diff --git a/libs/libcurl/src/mk-ca-bundle.pl b/libs/libcurl/src/mk-ca-bundle.pl
new file mode 100644
index 0000000000..18dc156905
--- /dev/null
+++ b/libs/libcurl/src/mk-ca-bundle.pl
@@ -0,0 +1,223 @@
+#!/usr/bin/perl -w
+# ***************************************************************************
+# * _ _ ____ _
+# * 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.
+# *
+# ***************************************************************************
+# This Perl script creates a fresh ca-bundle.crt file for use with libcurl.
+# It downloads certdata.txt from Mozilla's source tree (see URL below),
+# then parses certdata.txt and extracts CA Root Certificates into PEM format.
+# These are then processed with the OpenSSL commandline tool to produce the
+# final ca-bundle.crt file.
+# The script is based on the parse-certs script written by Roland Krikava.
+# This Perl script works on almost any platform since its only external
+# dependency is the OpenSSL commandline tool for optional text listing.
+# Hacked by Guenter Knauf.
+#
+use Getopt::Std;
+use MIME::Base64;
+use LWP::UserAgent;
+use strict;
+use vars qw($opt_b $opt_f $opt_h $opt_i $opt_l $opt_n $opt_q $opt_t $opt_u $opt_v);
+
+my $url = 'http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1';
+# If the OpenSSL commandline is not in search path you can configure it here!
+my $openssl = 'openssl';
+
+my $version = '1.17';
+
+getopts('bfhilnqtuv');
+
+if ($opt_i) {
+ print ("=" x 78 . "\n");
+ print "Script Version : $version\n";
+ print "Perl Version : $]\n";
+ print "Operating System Name : $^O\n";
+ print "Getopt::Std.pm Version : ${Getopt::Std::VERSION}\n";
+ print "MIME::Base64.pm Version : ${MIME::Base64::VERSION}\n";
+ print "LWP::UserAgent.pm Version : ${LWP::UserAgent::VERSION}\n";
+ print "LWP.pm Version : ${LWP::VERSION}\n";
+ print ("=" x 78 . "\n");
+}
+
+$0 =~ s@.*(/|\\)@@;
+if ($opt_h) {
+ printf("Usage:\t%s [-b] [-f] [-i] [-l] [-n] [-q] [-t] [-u] [-v] [<outputfile>]\n", $0);
+ print "\t-b\tbackup an existing version of ca-bundle.crt\n";
+ print "\t-f\tforce rebuild even if certdata.txt is current\n";
+ print "\t-i\tprint version info about used modules\n";
+ print "\t-l\tprint license info about certdata.txt\n";
+ print "\t-n\tno download of certdata.txt (to use existing)\n";
+ print "\t-q\tbe really quiet (no progress output at all)\n";
+ print "\t-t\tinclude plain text listing of certificates\n";
+ print "\t-u\tunlink (remove) certdata.txt after processing\n";
+ print "\t-v\tbe verbose and print out processed CAs\n";
+ exit;
+}
+
+my $crt = $ARGV[0] || 'ca-bundle.crt';
+(my $txt = $url) =~ s@(.*/|\?.*)@@g;
+
+my $stdout = $crt eq '-';
+my $resp;
+my $fetched;
+
+unless ($opt_n and -e $txt) {
+ print STDERR "Downloading '$txt' ...\n" if (!$opt_q);
+ my $ua = new LWP::UserAgent(agent => "$0/$version");
+ $ua->env_proxy();
+ $resp = $ua->mirror($url, $txt);
+ if ($resp && $resp->code eq '304') {
+ print STDERR "Not modified\n" unless $opt_q;
+ exit 0 if -e $crt && !$opt_f;
+ } else {
+ $fetched = 1;
+ }
+ if( !$resp || $resp->code !~ /^(?:200|304)$/ ) {
+ print STDERR "Unable to download latest data: "
+ . ($resp? $resp->code . ' - ' . $resp->message : "LWP failed") . "\n"
+ unless $opt_q;
+ exit 1 if -e $crt || ! -r $txt;
+ }
+}
+
+my $currentdate = scalar gmtime($fetched ? $resp->last_modified : (stat($txt))[9]);
+
+my $format = $opt_t ? "plain text and " : "";
+if( $stdout ) {
+ open(CRT, '> -') or die "Couldn't open STDOUT: $!\n";
+} else {
+ open(CRT,">$crt.~") or die "Couldn't open $crt.~: $!\n";
+}
+print CRT <<EOT;
+##
+## $crt -- Bundle of CA Root Certificates
+##
+## Certificate data from Mozilla as of: ${currentdate}
+##
+## This is a bundle of X.509 certificates of public Certificate Authorities
+## (CA). These were automatically extracted from Mozilla's root certificates
+## file (certdata.txt). This file can be found in the mozilla source tree:
+## $url
+##
+## It contains the certificates in ${format}PEM format and therefore
+## can be directly used with curl / libcurl / php_curl, or with
+## an Apache+mod_ssl webserver for SSL client authentication.
+## Just configure this file as the SSLCACertificateFile.
+##
+
+EOT
+
+print STDERR "Processing '$txt' ...\n" if (!$opt_q);
+my $caname;
+my $certnum = 0;
+my $skipnum = 0;
+my $start_of_cert = 0;
+
+open(TXT,"$txt") or die "Couldn't open $txt: $!\n";
+while (<TXT>) {
+ if (/\*\*\*\*\* BEGIN LICENSE BLOCK \*\*\*\*\*/) {
+ print CRT;
+ print if ($opt_l);
+ while (<TXT>) {
+ print CRT;
+ print if ($opt_l);
+ last if (/\*\*\*\*\* END LICENSE BLOCK \*\*\*\*\*/);
+ }
+ }
+ next if /^#|^\s*$/;
+ chomp;
+ if (/^CVS_ID\s+\"(.*)\"/) {
+ print CRT "# $1\n";
+ }
+
+ # this is a match for the start of a certificate
+ if (/^CKA_CLASS CK_OBJECT_CLASS CKO_CERTIFICATE/) {
+ $start_of_cert = 1
+ }
+ if ($start_of_cert && /^CKA_LABEL UTF8 \"(.*)\"/) {
+ $caname = $1;
+ }
+ my $untrusted = 0;
+ if ($start_of_cert && /^CKA_VALUE MULTILINE_OCTAL/) {
+ my $data;
+ while (<TXT>) {
+ last if (/^END/);
+ chomp;
+ my @octets = split(/\\/);
+ shift @octets;
+ for (@octets) {
+ $data .= chr(oct);
+ }
+ }
+ # scan forwards until the trust part
+ while (<TXT>) {
+ last if (/^CKA_CLASS CK_OBJECT_CLASS CKO_NSS_TRUST/);
+ chomp;
+ }
+ # now scan the trust part for untrusted certs
+ while (<TXT>) {
+ last if (/^#/);
+ if (/^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_NOT_TRUSTED$/
+ or /^CKA_TRUST_SERVER_AUTH\s+CK_TRUST\s+CKT_NSS_TRUST_UNKNOWN$/) {
+ $untrusted = 1;
+ }
+ }
+ if ($untrusted) {
+ $skipnum ++;
+ } else {
+ my $pem = "-----BEGIN CERTIFICATE-----\n"
+ . MIME::Base64::encode($data)
+ . "-----END CERTIFICATE-----\n";
+ print CRT "\n$caname\n";
+ print CRT ("=" x length($caname) . "\n");
+ if (!$opt_t) {
+ print CRT $pem;
+ }
+ if ($opt_t) {
+ open(TMP, "|$openssl x509 -md5 -fingerprint -text -inform PEM >> $crt") or die "Couldn't open openssl pipe: $!\n";
+ print TMP $pem;
+ close(TMP) or die "Couldn't close openssl pipe: $!\n";
+ }
+ print STDERR "Parsing: $caname\n" if ($opt_v);
+ $certnum ++;
+ $start_of_cert = 0;
+ }
+ }
+}
+close(TXT) or die "Couldn't close $txt: $!\n";
+close(CRT) or die "Couldn't close $crt.~: $!\n";
+unless( $stdout ) {
+ if ($opt_b && -e $crt) {
+ my $bk = 1;
+ while (-e "$crt.~${bk}~") {
+ $bk++;
+ }
+ rename $crt, "$crt.~${bk}~" or die "Failed to create backup $crt.~$bk}~: $!\n";
+ } elsif( -e $crt ) {
+ unlink( $crt ) or die "Failed to remove $crt: $!\n";
+ }
+ rename "$crt.~", $crt or die "Failed to rename $crt.~ to $crt: $!\n";
+}
+unlink $txt if ($opt_u);
+print STDERR "Done ($certnum CA certs processed, $skipnum untrusted skipped).\n" if (!$opt_q);
+
+exit;
+
+
diff --git a/libs/libcurl/src/mprintf.c b/libs/libcurl/src/mprintf.c
new file mode 100644
index 0000000000..8f392c7f29
--- /dev/null
+++ b/libs/libcurl/src/mprintf.c
@@ -0,0 +1,1098 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1999 - 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.
+ *
+ *
+ * Purpose:
+ * A merge of Bjorn Reese's format() function and Daniel's dsprintf()
+ * 1.0. A full blooded printf() clone with full support for <num>$
+ * everywhere (parameters, widths and precisions) including variabled
+ * sized parameters (like doubles, long longs, long doubles and even
+ * void * in 64-bit architectures).
+ *
+ * Current restrictions:
+ * - Max 128 parameters
+ * - No 'long double' support.
+ *
+ * If you ever want truly portable and good *printf() clones, the project that
+ * took on from here is named 'Trio' and you find more details on the trio web
+ * page at http://daniel.haxx.se/trio/
+ */
+
+#include "curl_setup.h"
+
+#if defined(DJGPP) && (DJGPP_MINOR < 4)
+#undef _MPRINTF_REPLACE /* don't use x_was_used() here */
+#endif
+
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef SIZEOF_LONG_DOUBLE
+#define SIZEOF_LONG_DOUBLE 0
+#endif
+
+/*
+ * If SIZEOF_SIZE_T has not been defined, default to the size of long.
+ */
+
+#ifndef SIZEOF_SIZE_T
+# define SIZEOF_SIZE_T CURL_SIZEOF_LONG
+#endif
+
+#ifdef HAVE_LONGLONG
+# define LONG_LONG_TYPE long long
+# define HAVE_LONG_LONG_TYPE
+#else
+# if defined(_MSC_VER) && (_MSC_VER >= 900) && (_INTEGRAL_MAX_BITS >= 64)
+# define LONG_LONG_TYPE __int64
+# define HAVE_LONG_LONG_TYPE
+# else
+# undef LONG_LONG_TYPE
+# undef HAVE_LONG_LONG_TYPE
+# endif
+#endif
+
+/*
+ * Max integer data types that mprintf.c is capable
+ */
+
+#ifdef HAVE_LONG_LONG_TYPE
+# define mp_intmax_t LONG_LONG_TYPE
+# define mp_uintmax_t unsigned LONG_LONG_TYPE
+#else
+# define mp_intmax_t long
+# define mp_uintmax_t unsigned long
+#endif
+
+#define BUFFSIZE 256 /* buffer for long-to-str and float-to-str calcs */
+#define MAX_PARAMETERS 128 /* lame static limit */
+
+#ifdef __AMIGA__
+# undef FORMAT_INT
+#endif
+
+/* Lower-case digits. */
+static const char lower_digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+/* Upper-case digits. */
+static const char upper_digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+#define OUTCHAR(x) \
+ do{ \
+ if(stream((unsigned char)(x), (FILE *)data) != -1) \
+ done++; \
+ else \
+ return done; /* return immediately on failure */ \
+ } WHILE_FALSE
+
+/* Data type to read from the arglist */
+typedef enum {
+ FORMAT_UNKNOWN = 0,
+ FORMAT_STRING,
+ FORMAT_PTR,
+ FORMAT_INT,
+ FORMAT_INTPTR,
+ FORMAT_LONG,
+ FORMAT_LONGLONG,
+ FORMAT_DOUBLE,
+ FORMAT_LONGDOUBLE,
+ FORMAT_WIDTH /* For internal use */
+} FormatType;
+
+/* conversion and display flags */
+enum {
+ FLAGS_NEW = 0,
+ FLAGS_SPACE = 1<<0,
+ FLAGS_SHOWSIGN = 1<<1,
+ FLAGS_LEFT = 1<<2,
+ FLAGS_ALT = 1<<3,
+ FLAGS_SHORT = 1<<4,
+ FLAGS_LONG = 1<<5,
+ FLAGS_LONGLONG = 1<<6,
+ FLAGS_LONGDOUBLE = 1<<7,
+ FLAGS_PAD_NIL = 1<<8,
+ FLAGS_UNSIGNED = 1<<9,
+ FLAGS_OCTAL = 1<<10,
+ FLAGS_HEX = 1<<11,
+ FLAGS_UPPER = 1<<12,
+ FLAGS_WIDTH = 1<<13, /* '*' or '*<num>$' used */
+ FLAGS_WIDTHPARAM = 1<<14, /* width PARAMETER was specified */
+ FLAGS_PREC = 1<<15, /* precision was specified */
+ FLAGS_PRECPARAM = 1<<16, /* precision PARAMETER was specified */
+ FLAGS_CHAR = 1<<17, /* %c story */
+ FLAGS_FLOATE = 1<<18, /* %e or %E */
+ FLAGS_FLOATG = 1<<19 /* %g or %G */
+};
+
+typedef struct {
+ FormatType type;
+ int flags;
+ long width; /* width OR width parameter number */
+ long precision; /* precision OR precision parameter number */
+ union {
+ char *str;
+ void *ptr;
+ union {
+ mp_intmax_t as_signed;
+ mp_uintmax_t as_unsigned;
+ } num;
+ double dnum;
+ } data;
+} va_stack_t;
+
+struct nsprintf {
+ char *buffer;
+ size_t length;
+ size_t max;
+};
+
+struct asprintf {
+ char *buffer; /* allocated buffer */
+ size_t len; /* length of string */
+ size_t alloc; /* length of alloc */
+ int fail; /* (!= 0) if an alloc has failed and thus
+ the output is not the complete data */
+};
+
+static long dprintf_DollarString(char *input, char **end)
+{
+ int number=0;
+ while(ISDIGIT(*input)) {
+ number *= 10;
+ number += *input-'0';
+ input++;
+ }
+ if(number && ('$'==*input++)) {
+ *end = input;
+ return number;
+ }
+ return 0;
+}
+
+static int dprintf_IsQualifierNoDollar(char c)
+{
+ switch (c) {
+ case '-': case '+': case ' ': case '#': case '.':
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case 'h': case 'l': case 'L': case 'z': case 'q':
+ case '*': case 'O':
+ return 1; /* true */
+ default:
+ return 0; /* false */
+ }
+}
+
+/******************************************************************
+ *
+ * Pass 1:
+ * Create an index with the type of each parameter entry and its
+ * value (may vary in size)
+ *
+ ******************************************************************/
+
+static long dprintf_Pass1(const char *format, va_stack_t *vto, char **endpos,
+ va_list arglist)
+{
+ char *fmt = (char *)format;
+ int param_num = 0;
+ long this_param;
+ long width;
+ long precision;
+ int flags;
+ long max_param=0;
+ long i;
+
+ while(*fmt) {
+ if(*fmt++ == '%') {
+ if(*fmt == '%') {
+ fmt++;
+ continue; /* while */
+ }
+
+ flags = FLAGS_NEW;
+
+ /* Handle the positional case (N$) */
+
+ param_num++;
+
+ this_param = dprintf_DollarString(fmt, &fmt);
+ if(0 == this_param)
+ /* we got no positional, get the next counter */
+ this_param = param_num;
+
+ if(this_param > max_param)
+ max_param = this_param;
+
+ /*
+ * The parameter with number 'i' should be used. Next, we need
+ * to get SIZE and TYPE of the parameter. Add the information
+ * to our array.
+ */
+
+ width = 0;
+ precision = 0;
+
+ /* Handle the flags */
+
+ while(dprintf_IsQualifierNoDollar(*fmt)) {
+ switch (*fmt++) {
+ case ' ':
+ flags |= FLAGS_SPACE;
+ break;
+ case '+':
+ flags |= FLAGS_SHOWSIGN;
+ break;
+ case '-':
+ flags |= FLAGS_LEFT;
+ flags &= ~FLAGS_PAD_NIL;
+ break;
+ case '#':
+ flags |= FLAGS_ALT;
+ break;
+ case '.':
+ flags |= FLAGS_PREC;
+ if('*' == *fmt) {
+ /* The precision is picked from a specified parameter */
+
+ flags |= FLAGS_PRECPARAM;
+ fmt++;
+ param_num++;
+
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ precision = i;
+ else
+ precision = param_num;
+
+ if(precision > max_param)
+ max_param = precision;
+ }
+ else {
+ flags |= FLAGS_PREC;
+ precision = strtol(fmt, &fmt, 10);
+ }
+ break;
+ case 'h':
+ flags |= FLAGS_SHORT;
+ break;
+ case 'l':
+ if(flags & FLAGS_LONG)
+ flags |= FLAGS_LONGLONG;
+ else
+ flags |= FLAGS_LONG;
+ break;
+ case 'L':
+ flags |= FLAGS_LONGDOUBLE;
+ break;
+ case 'q':
+ flags |= FLAGS_LONGLONG;
+ break;
+ case 'z':
+ /* the code below generates a warning if -Wunreachable-code is
+ used */
+#if (SIZEOF_SIZE_T > CURL_SIZEOF_LONG)
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+ case 'O':
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+ flags |= FLAGS_LONGLONG;
+#else
+ flags |= FLAGS_LONG;
+#endif
+ break;
+ case '0':
+ if(!(flags & FLAGS_LEFT))
+ flags |= FLAGS_PAD_NIL;
+ /* FALLTHROUGH */
+ case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ flags |= FLAGS_WIDTH;
+ width = strtol(fmt-1, &fmt, 10);
+ break;
+ case '*': /* Special case */
+ flags |= FLAGS_WIDTHPARAM;
+ param_num++;
+
+ i = dprintf_DollarString(fmt, &fmt);
+ if(i)
+ width = i;
+ else
+ width = param_num;
+ if(width > max_param)
+ max_param=width;
+ break;
+ default:
+ break;
+ }
+ } /* switch */
+
+ /* Handle the specifier */
+
+ i = this_param - 1;
+
+ switch (*fmt) {
+ case 'S':
+ flags |= FLAGS_ALT;
+ /* FALLTHROUGH */
+ case 's':
+ vto[i].type = FORMAT_STRING;
+ break;
+ case 'n':
+ vto[i].type = FORMAT_INTPTR;
+ break;
+ case 'p':
+ vto[i].type = FORMAT_PTR;
+ break;
+ case 'd': case 'i':
+ vto[i].type = FORMAT_INT;
+ break;
+ case 'u':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_UNSIGNED;
+ break;
+ case 'o':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_OCTAL;
+ break;
+ case 'x':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_HEX|FLAGS_UNSIGNED;
+ break;
+ case 'X':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_HEX|FLAGS_UPPER|FLAGS_UNSIGNED;
+ break;
+ case 'c':
+ vto[i].type = FORMAT_INT;
+ flags |= FLAGS_CHAR;
+ break;
+ case 'f':
+ vto[i].type = FORMAT_DOUBLE;
+ break;
+ case 'e':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATE;
+ break;
+ case 'E':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATE|FLAGS_UPPER;
+ break;
+ case 'g':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATG;
+ break;
+ case 'G':
+ vto[i].type = FORMAT_DOUBLE;
+ flags |= FLAGS_FLOATG|FLAGS_UPPER;
+ break;
+ default:
+ vto[i].type = FORMAT_UNKNOWN;
+ break;
+ } /* switch */
+
+ vto[i].flags = flags;
+ vto[i].width = width;
+ vto[i].precision = precision;
+
+ if(flags & FLAGS_WIDTHPARAM) {
+ /* we have the width specified from a parameter, so we make that
+ parameter's info setup properly */
+ vto[i].width = width - 1;
+ i = width - 1;
+ vto[i].type = FORMAT_WIDTH;
+ vto[i].flags = FLAGS_NEW;
+ vto[i].precision = vto[i].width = 0; /* can't use width or precision
+ of width! */
+ }
+ if(flags & FLAGS_PRECPARAM) {
+ /* we have the precision specified from a parameter, so we make that
+ parameter's info setup properly */
+ vto[i].precision = precision - 1;
+ i = precision - 1;
+ vto[i].type = FORMAT_WIDTH;
+ vto[i].flags = FLAGS_NEW;
+ vto[i].precision = vto[i].width = 0; /* can't use width or precision
+ of width! */
+ }
+ *endpos++ = fmt + 1; /* end of this sequence */
+ }
+ }
+
+ /* Read the arg list parameters into our data list */
+ for(i=0; i<max_param; i++) {
+ if((i + 1 < max_param) && (vto[i + 1].type == FORMAT_WIDTH)) {
+ /* Width/precision arguments must be read before the main argument
+ * they are attached to
+ */
+ vto[i + 1].data.num.as_signed = (mp_intmax_t)va_arg(arglist, int);
+ }
+
+ switch (vto[i].type) {
+ case FORMAT_STRING:
+ vto[i].data.str = va_arg(arglist, char *);
+ break;
+
+ case FORMAT_INTPTR:
+ case FORMAT_UNKNOWN:
+ case FORMAT_PTR:
+ vto[i].data.ptr = va_arg(arglist, void *);
+ break;
+
+ case FORMAT_INT:
+#ifdef HAVE_LONG_LONG_TYPE
+ if((vto[i].flags & FLAGS_LONGLONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, mp_uintmax_t);
+ else if(vto[i].flags & FLAGS_LONGLONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, mp_intmax_t);
+ else
+#endif
+ {
+ if((vto[i].flags & FLAGS_LONG) && (vto[i].flags & FLAGS_UNSIGNED))
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned long);
+ else if(vto[i].flags & FLAGS_LONG)
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, long);
+ else if(vto[i].flags & FLAGS_UNSIGNED)
+ vto[i].data.num.as_unsigned =
+ (mp_uintmax_t)va_arg(arglist, unsigned int);
+ else
+ vto[i].data.num.as_signed =
+ (mp_intmax_t)va_arg(arglist, int);
+ }
+ break;
+
+ case FORMAT_DOUBLE:
+ vto[i].data.dnum = va_arg(arglist, double);
+ break;
+
+ case FORMAT_WIDTH:
+ /* Argument has been read. Silently convert it into an integer
+ * for later use
+ */
+ vto[i].type = FORMAT_INT;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return max_param;
+
+}
+
+static int dprintf_formatf(
+ void *data, /* untouched by format(), just sent to the stream() function in
+ the second argument */
+ /* function pointer called for each output character */
+ int (*stream)(int, FILE *),
+ const char *format, /* %-formatted string */
+ va_list ap_save) /* list of parameters */
+{
+ /* Base-36 digits for numbers. */
+ const char *digits = lower_digits;
+
+ /* Pointer into the format string. */
+ char *f;
+
+ /* Number of characters written. */
+ int done = 0;
+
+ long param; /* current parameter to read */
+ long param_num=0; /* parameter counter */
+
+ va_stack_t vto[MAX_PARAMETERS];
+ char *endpos[MAX_PARAMETERS];
+ char **end;
+
+ char work[BUFFSIZE];
+
+ va_stack_t *p;
+
+ /* Do the actual %-code parsing */
+ dprintf_Pass1(format, vto, endpos, ap_save);
+
+ end = &endpos[0]; /* the initial end-position from the list dprintf_Pass1()
+ created for us */
+
+ f = (char *)format;
+ while(*f != '\0') {
+ /* Format spec modifiers. */
+ int is_alt;
+
+ /* Width of a field. */
+ long width;
+
+ /* Precision of a field. */
+ long prec;
+
+ /* Decimal integer is negative. */
+ int is_neg;
+
+ /* Base of a number to be written. */
+ long base;
+
+ /* Integral values to be written. */
+ mp_uintmax_t num;
+
+ /* Used to convert negative in positive. */
+ mp_intmax_t signed_num;
+
+ if(*f != '%') {
+ /* This isn't a format spec, so write everything out until the next one
+ OR end of string is reached. */
+ do {
+ OUTCHAR(*f);
+ } while(*++f && ('%' != *f));
+ continue;
+ }
+
+ ++f;
+
+ /* Check for "%%". Note that although the ANSI standard lists
+ '%' as a conversion specifier, it says "The complete format
+ specification shall be `%%'," so we can avoid all the width
+ and precision processing. */
+ if(*f == '%') {
+ ++f;
+ OUTCHAR('%');
+ continue;
+ }
+
+ /* If this is a positional parameter, the position must follow immediately
+ after the %, thus create a %<num>$ sequence */
+ param=dprintf_DollarString(f, &f);
+
+ if(!param)
+ param = param_num;
+ else
+ --param;
+
+ param_num++; /* increase this always to allow "%2$s %1$s %s" and then the
+ third %s will pick the 3rd argument */
+
+ p = &vto[param];
+
+ /* pick up the specified width */
+ if(p->flags & FLAGS_WIDTHPARAM)
+ width = (long)vto[p->width].data.num.as_signed;
+ else
+ width = p->width;
+
+ /* pick up the specified precision */
+ if(p->flags & FLAGS_PRECPARAM) {
+ prec = (long)vto[p->precision].data.num.as_signed;
+ param_num++; /* since the precision is extraced from a parameter, we
+ must skip that to get to the next one properly */
+ }
+ else if(p->flags & FLAGS_PREC)
+ prec = p->precision;
+ else
+ prec = -1;
+
+ is_alt = (p->flags & FLAGS_ALT) ? 1 : 0;
+
+ switch (p->type) {
+ case FORMAT_INT:
+ num = p->data.num.as_unsigned;
+ if(p->flags & FLAGS_CHAR) {
+ /* Character. */
+ if(!(p->flags & FLAGS_LEFT))
+ while(--width > 0)
+ OUTCHAR(' ');
+ OUTCHAR((char) num);
+ if(p->flags & FLAGS_LEFT)
+ while(--width > 0)
+ OUTCHAR(' ');
+ break;
+ }
+ if(p->flags & FLAGS_OCTAL) {
+ /* Octal unsigned integer. */
+ base = 8;
+ goto unsigned_number;
+ }
+ else if(p->flags & FLAGS_HEX) {
+ /* Hexadecimal unsigned integer. */
+
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ base = 16;
+ goto unsigned_number;
+ }
+ else if(p->flags & FLAGS_UNSIGNED) {
+ /* Decimal unsigned integer. */
+ base = 10;
+ goto unsigned_number;
+ }
+
+ /* Decimal integer. */
+ base = 10;
+
+ is_neg = (p->data.num.as_signed < (mp_intmax_t)0) ? 1 : 0;
+ if(is_neg) {
+ /* signed_num might fail to hold absolute negative minimum by 1 */
+ signed_num = p->data.num.as_signed + (mp_intmax_t)1;
+ signed_num = -signed_num;
+ num = (mp_uintmax_t)signed_num;
+ num += (mp_uintmax_t)1;
+ }
+
+ goto number;
+
+ unsigned_number:
+ /* Unsigned number of base BASE. */
+ is_neg = 0;
+
+ number:
+ /* Number of base BASE. */
+ {
+ char *workend = &work[sizeof(work) - 1];
+ char *w;
+
+ /* Supply a default precision if none was given. */
+ if(prec == -1)
+ prec = 1;
+
+ /* Put the number in WORK. */
+ w = workend;
+ while(num > 0) {
+ *w-- = digits[num % base];
+ num /= base;
+ }
+ width -= (long)(workend - w);
+ prec -= (long)(workend - w);
+
+ if(is_alt && base == 8 && prec <= 0) {
+ *w-- = '0';
+ --width;
+ }
+
+ if(prec > 0) {
+ width -= prec;
+ while(prec-- > 0)
+ *w-- = '0';
+ }
+
+ if(is_alt && base == 16)
+ width -= 2;
+
+ if(is_neg || (p->flags & FLAGS_SHOWSIGN) || (p->flags & FLAGS_SPACE))
+ --width;
+
+ if(!(p->flags & FLAGS_LEFT) && !(p->flags & FLAGS_PAD_NIL))
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ if(is_neg)
+ OUTCHAR('-');
+ else if(p->flags & FLAGS_SHOWSIGN)
+ OUTCHAR('+');
+ else if(p->flags & FLAGS_SPACE)
+ OUTCHAR(' ');
+
+ if(is_alt && base == 16) {
+ OUTCHAR('0');
+ if(p->flags & FLAGS_UPPER)
+ OUTCHAR('X');
+ else
+ OUTCHAR('x');
+ }
+
+ if(!(p->flags & FLAGS_LEFT) && (p->flags & FLAGS_PAD_NIL))
+ while(width-- > 0)
+ OUTCHAR('0');
+
+ /* Write the number. */
+ while(++w <= workend) {
+ OUTCHAR(*w);
+ }
+
+ if(p->flags & FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+ }
+ break;
+
+ case FORMAT_STRING:
+ /* String. */
+ {
+ static const char null[] = "(nil)";
+ const char *str;
+ size_t len;
+
+ str = (char *) p->data.str;
+ if(str == NULL) {
+ /* Write null[] if there's space. */
+ if(prec == -1 || prec >= (long) sizeof(null) - 1) {
+ str = null;
+ len = sizeof(null) - 1;
+ /* Disable quotes around (nil) */
+ p->flags &= (~FLAGS_ALT);
+ }
+ else {
+ str = "";
+ len = 0;
+ }
+ }
+ else
+ len = strlen(str);
+
+ if(prec != -1 && (size_t) prec < len)
+ len = (size_t)prec;
+ width -= (long)len;
+
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
+
+ if(!(p->flags&FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ while(len-- > 0)
+ OUTCHAR(*str++);
+ if(p->flags&FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+
+ if(p->flags & FLAGS_ALT)
+ OUTCHAR('"');
+ }
+ break;
+
+ case FORMAT_PTR:
+ /* Generic pointer. */
+ {
+ void *ptr;
+ ptr = (void *) p->data.ptr;
+ if(ptr != NULL) {
+ /* If the pointer is not NULL, write it as a %#x spec. */
+ base = 16;
+ digits = (p->flags & FLAGS_UPPER)? upper_digits : lower_digits;
+ is_alt = 1;
+ num = (size_t) ptr;
+ is_neg = 0;
+ goto number;
+ }
+ else {
+ /* Write "(nil)" for a nil pointer. */
+ static const char strnil[] = "(nil)";
+ const char *point;
+
+ width -= (long)(sizeof(strnil) - 1);
+ if(p->flags & FLAGS_LEFT)
+ while(width-- > 0)
+ OUTCHAR(' ');
+ for(point = strnil; *point != '\0'; ++point)
+ OUTCHAR(*point);
+ if(! (p->flags & FLAGS_LEFT))
+ while(width-- > 0)
+ OUTCHAR(' ');
+ }
+ }
+ break;
+
+ case FORMAT_DOUBLE:
+ {
+ char formatbuf[32]="%";
+ char *fptr = &formatbuf[1];
+ size_t left = sizeof(formatbuf)-strlen(formatbuf);
+ int len;
+
+ width = -1;
+ if(p->flags & FLAGS_WIDTH)
+ width = p->width;
+ else if(p->flags & FLAGS_WIDTHPARAM)
+ width = (long)vto[p->width].data.num.as_signed;
+
+ prec = -1;
+ if(p->flags & FLAGS_PREC)
+ prec = p->precision;
+ else if(p->flags & FLAGS_PRECPARAM)
+ prec = (long)vto[p->precision].data.num.as_signed;
+
+ if(p->flags & FLAGS_LEFT)
+ *fptr++ = '-';
+ if(p->flags & FLAGS_SHOWSIGN)
+ *fptr++ = '+';
+ if(p->flags & FLAGS_SPACE)
+ *fptr++ = ' ';
+ if(p->flags & FLAGS_ALT)
+ *fptr++ = '#';
+
+ *fptr = 0;
+
+ if(width >= 0) {
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, "%ld", width);
+ fptr += len;
+ left -= len;
+ }
+ if(prec >= 0) {
+ /* RECURSIVE USAGE */
+ len = curl_msnprintf(fptr, left, ".%ld", prec);
+ fptr += len;
+ }
+ if(p->flags & FLAGS_LONG)
+ *fptr++ = 'l';
+
+ if(p->flags & FLAGS_FLOATE)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'E':'e');
+ else if(p->flags & FLAGS_FLOATG)
+ *fptr++ = (char)((p->flags & FLAGS_UPPER) ? 'G' : 'g');
+ else
+ *fptr++ = 'f';
+
+ *fptr = 0; /* and a final zero termination */
+
+ /* NOTE NOTE NOTE!! Not all sprintf implementations return number of
+ output characters */
+ (sprintf)(work, formatbuf, p->data.dnum);
+
+ for(fptr=work; *fptr; fptr++)
+ OUTCHAR(*fptr);
+ }
+ break;
+
+ case FORMAT_INTPTR:
+ /* Answer the count of characters written. */
+#ifdef HAVE_LONG_LONG_TYPE
+ if(p->flags & FLAGS_LONGLONG)
+ *(LONG_LONG_TYPE *) p->data.ptr = (LONG_LONG_TYPE)done;
+ else
+#endif
+ if(p->flags & FLAGS_LONG)
+ *(long *) p->data.ptr = (long)done;
+ else if(!(p->flags & FLAGS_SHORT))
+ *(int *) p->data.ptr = (int)done;
+ else
+ *(short *) p->data.ptr = (short)done;
+ break;
+
+ default:
+ break;
+ }
+ f = *end++; /* goto end of %-code */
+
+ }
+ return done;
+}
+
+/* fputc() look-alike */
+static int addbyter(int output, FILE *data)
+{
+ struct nsprintf *infop=(struct nsprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
+ if(infop->length < infop->max) {
+ /* only do this if we haven't reached max length yet */
+ infop->buffer[0] = outc; /* store */
+ infop->buffer++; /* increase pointer */
+ infop->length++; /* we are now one byte larger */
+ return outc; /* fputc() returns like this on success */
+ }
+ return -1;
+}
+
+int curl_mvsnprintf(char *buffer, size_t maxlength, const char *format,
+ va_list ap_save)
+{
+ int retcode;
+ struct nsprintf info;
+
+ info.buffer = buffer;
+ info.length = 0;
+ info.max = maxlength;
+
+ retcode = dprintf_formatf(&info, addbyter, format, ap_save);
+ if(info.max) {
+ /* we terminate this with a zero byte */
+ if(info.max == info.length)
+ /* we're at maximum, scrap the last letter */
+ info.buffer[-1] = 0;
+ else
+ info.buffer[0] = 0;
+ }
+ return retcode;
+}
+
+int curl_msnprintf(char *buffer, size_t maxlength, const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+ retcode = curl_mvsnprintf(buffer, maxlength, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+/* fputc() look-alike */
+static int alloc_addbyter(int output, FILE *data)
+{
+ struct asprintf *infop=(struct asprintf *)data;
+ unsigned char outc = (unsigned char)output;
+
+ if(!infop->buffer) {
+ infop->buffer = malloc(32);
+ if(!infop->buffer) {
+ infop->fail = 1;
+ return -1; /* fail */
+ }
+ infop->alloc = 32;
+ infop->len =0;
+ }
+ else if(infop->len+1 >= infop->alloc) {
+ char *newptr;
+
+ newptr = realloc(infop->buffer, infop->alloc*2);
+
+ if(!newptr) {
+ infop->fail = 1;
+ return -1; /* fail */
+ }
+ infop->buffer = newptr;
+ infop->alloc *= 2;
+ }
+
+ infop->buffer[ infop->len ] = outc;
+
+ infop->len++;
+
+ return outc; /* fputc() returns like this on success */
+}
+
+char *curl_maprintf(const char *format, ...)
+{
+ va_list ap_save; /* argument pointer */
+ int retcode;
+ struct asprintf info;
+
+ info.buffer = NULL;
+ info.len = 0;
+ info.alloc = 0;
+ info.fail = 0;
+
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ va_end(ap_save);
+ if((-1 == retcode) || info.fail) {
+ if(info.alloc)
+ free(info.buffer);
+ return NULL;
+ }
+ if(info.alloc) {
+ info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ else
+ return strdup("");
+}
+
+char *curl_mvaprintf(const char *format, va_list ap_save)
+{
+ int retcode;
+ struct asprintf info;
+
+ info.buffer = NULL;
+ info.len = 0;
+ info.alloc = 0;
+ info.fail = 0;
+
+ retcode = dprintf_formatf(&info, alloc_addbyter, format, ap_save);
+ if((-1 == retcode) || info.fail) {
+ if(info.alloc)
+ free(info.buffer);
+ return NULL;
+ }
+
+ if(info.alloc) {
+ info.buffer[info.len] = 0; /* we terminate this with a zero byte */
+ return info.buffer;
+ }
+ else
+ return strdup("");
+}
+
+static int storebuffer(int output, FILE *data)
+{
+ char **buffer = (char **)data;
+ unsigned char outc = (unsigned char)output;
+ **buffer = outc;
+ (*buffer)++;
+ return outc; /* act like fputc() ! */
+}
+
+int curl_msprintf(char *buffer, const char *format, ...)
+{
+ va_list ap_save; /* argument pointer */
+ int retcode;
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+ va_end(ap_save);
+ *buffer=0; /* we terminate this with a zero byte */
+ return retcode;
+}
+
+int curl_mprintf(const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+
+ retcode = dprintf_formatf(stdout, fputc, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+int curl_mfprintf(FILE *whereto, const char *format, ...)
+{
+ int retcode;
+ va_list ap_save; /* argument pointer */
+ va_start(ap_save, format);
+ retcode = dprintf_formatf(whereto, fputc, format, ap_save);
+ va_end(ap_save);
+ return retcode;
+}
+
+int curl_mvsprintf(char *buffer, const char *format, va_list ap_save)
+{
+ int retcode;
+ retcode = dprintf_formatf(&buffer, storebuffer, format, ap_save);
+ *buffer=0; /* we terminate this with a zero byte */
+ return retcode;
+}
+
+int curl_mvprintf(const char *format, va_list ap_save)
+{
+ return dprintf_formatf(stdout, fputc, format, ap_save);
+}
+
+int curl_mvfprintf(FILE *whereto, const char *format, va_list ap_save)
+{
+ return dprintf_formatf(whereto, fputc, format, ap_save);
+}
diff --git a/libs/libcurl/src/multi.c b/libs/libcurl/src/multi.c
new file mode 100644
index 0000000000..e723a3ebf0
--- /dev/null
+++ b/libs/libcurl/src/multi.c
@@ -0,0 +1,2702 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 <curl/curl.h>
+
+#include "urldata.h"
+#include "transfer.h"
+#include "url.h"
+#include "connect.h"
+#include "progress.h"
+#include "easyif.h"
+#include "multiif.h"
+#include "sendf.h"
+#include "timeval.h"
+#include "http.h"
+#include "select.h"
+#include "warnless.h"
+#include "speedcheck.h"
+#include "conncache.h"
+#include "bundles.h"
+#include "multihandle.h"
+#include "pipeline.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"
+
+/*
+ CURL_SOCKET_HASH_TABLE_SIZE should be a prime number. Increasing it from 97
+ to 911 takes on a 32-bit machine 4 x 804 = 3211 more bytes. Still, every
+ CURL handle takes 45-50 K memory, therefore this 3K are not significant.
+*/
+#ifndef CURL_SOCKET_HASH_TABLE_SIZE
+#define CURL_SOCKET_HASH_TABLE_SIZE 911
+#endif
+
+#define CURL_CONNECTION_HASH_SIZE 97
+
+#define CURL_MULTI_HANDLE 0x000bab1e
+
+#define GOOD_MULTI_HANDLE(x) \
+ ((x) && (((struct Curl_multi *)(x))->type == CURL_MULTI_HANDLE))
+#define GOOD_EASY_HANDLE(x) \
+ ((x) && (((struct SessionHandle *)(x))->magic == CURLEASY_MAGIC_NUMBER))
+
+static void singlesocket(struct Curl_multi *multi,
+ struct SessionHandle *data);
+static int update_timer(struct Curl_multi *multi);
+
+static bool isHandleAtHead(struct SessionHandle *handle,
+ struct curl_llist *pipeline);
+static CURLMcode add_next_timeout(struct timeval now,
+ struct Curl_multi *multi,
+ struct SessionHandle *d);
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms);
+
+#ifdef DEBUGBUILD
+static const char * const statename[]={
+ "INIT",
+ "CONNECT_PEND",
+ "CONNECT",
+ "WAITRESOLVE",
+ "WAITCONNECT",
+ "WAITPROXYCONNECT",
+ "PROTOCONNECT",
+ "WAITDO",
+ "DO",
+ "DOING",
+ "DO_MORE",
+ "DO_DONE",
+ "WAITPERFORM",
+ "PERFORM",
+ "TOOFAST",
+ "DONE",
+ "COMPLETED",
+ "MSGSENT",
+};
+#endif
+
+static void multi_freetimeout(void *a, void *b);
+
+/* always use this function to change state, to make debugging easier */
+static void mstate(struct SessionHandle *data, CURLMstate state
+#ifdef DEBUGBUILD
+ , int lineno
+#endif
+)
+{
+#ifdef DEBUGBUILD
+ long connection_id = -5000;
+#endif
+ CURLMstate oldstate = data->mstate;
+
+ if(oldstate == state)
+ /* don't bother when the new state is the same as the old state */
+ return;
+
+ data->mstate = state;
+
+#ifdef DEBUGBUILD
+ if(data->mstate >= CURLM_STATE_CONNECT_PEND &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ if(data->easy_conn)
+ connection_id = data->easy_conn->connection_id;
+
+ infof(data,
+ "STATE: %s => %s handle %p; line %d (connection #%ld) \n",
+ statename[oldstate], statename[data->mstate],
+ (void *)data, lineno, connection_id);
+ }
+#endif
+ if(state == CURLM_STATE_COMPLETED)
+ /* changing to COMPLETED means there's one less easy handle 'alive' */
+ data->multi->num_alive--;
+}
+
+#ifndef DEBUGBUILD
+#define multistate(x,y) mstate(x,y)
+#else
+#define multistate(x,y) mstate(x,y, __LINE__)
+#endif
+
+/*
+ * We add one of these structs to the sockhash for a particular socket
+ */
+
+struct Curl_sh_entry {
+ struct SessionHandle *easy;
+ time_t timestamp;
+ int action; /* what action READ/WRITE this socket waits for */
+ curl_socket_t socket; /* mainly to ease debugging */
+ void *socketp; /* settable by users with curl_multi_assign() */
+};
+/* bits for 'action' having no bits means this socket is not expecting any
+ action */
+#define SH_READ 1
+#define SH_WRITE 2
+
+/* make sure this socket is present in the hash for this handle */
+static struct Curl_sh_entry *sh_addentry(struct curl_hash *sh,
+ curl_socket_t s,
+ struct SessionHandle *data)
+{
+ struct Curl_sh_entry *there =
+ Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+ struct Curl_sh_entry *check;
+
+ if(there)
+ /* it is present, return fine */
+ return there;
+
+ /* not present, add it */
+ check = calloc(1, sizeof(struct Curl_sh_entry));
+ if(!check)
+ return NULL; /* major failure */
+ check->easy = data;
+ check->socket = s;
+
+ /* make/add new hash entry */
+ if(NULL == Curl_hash_add(sh, (char *)&s, sizeof(curl_socket_t), check)) {
+ free(check);
+ return NULL; /* major failure */
+ }
+
+ return check; /* things are good in sockhash land */
+}
+
+
+/* delete the given socket + handle from the hash */
+static void sh_delentry(struct curl_hash *sh, curl_socket_t s)
+{
+ struct Curl_sh_entry *there =
+ Curl_hash_pick(sh, (char *)&s, sizeof(curl_socket_t));
+
+ if(there) {
+ /* this socket is in the hash */
+ /* We remove the hash entry. (This'll end up in a call to
+ sh_freeentry().) */
+ Curl_hash_delete(sh, (char *)&s, sizeof(curl_socket_t));
+ }
+}
+
+/*
+ * free a sockhash entry
+ */
+static void sh_freeentry(void *freethis)
+{
+ struct Curl_sh_entry *p = (struct Curl_sh_entry *) freethis;
+
+ if(p)
+ free(p);
+}
+
+static size_t fd_key_compare(void *k1, size_t k1_len, void *k2, size_t k2_len)
+{
+ (void) k1_len; (void) k2_len;
+
+ return (*((int *) k1)) == (*((int *) k2));
+}
+
+static size_t hash_fd(void *key, size_t key_length, size_t slots_num)
+{
+ int fd = *((int *) key);
+ (void) key_length;
+
+ return (fd % (int)slots_num);
+}
+
+/*
+ * sh_init() creates a new socket hash and returns the handle for it.
+ *
+ * Quote from README.multi_socket:
+ *
+ * "Some tests at 7000 and 9000 connections showed that the socket hash lookup
+ * is somewhat of a bottle neck. Its current implementation may be a bit too
+ * limiting. It simply has a fixed-size array, and on each entry in the array
+ * it has a linked list with entries. So the hash only checks which list to
+ * scan through. The code I had used so for used a list with merely 7 slots
+ * (as that is what the DNS hash uses) but with 7000 connections that would
+ * make an average of 1000 nodes in each list to run through. I upped that to
+ * 97 slots (I believe a prime is suitable) and noticed a significant speed
+ * increase. I need to reconsider the hash implementation or use a rather
+ * large default value like this. At 9000 connections I was still below 10us
+ * per call."
+ *
+ */
+static struct curl_hash *sh_init(int hashsize)
+{
+ return Curl_hash_alloc(hashsize, hash_fd, fd_key_compare,
+ sh_freeentry);
+}
+
+/*
+ * multi_addmsg()
+ *
+ * Called when a transfer is completed. Adds the given msg pointer to
+ * the list kept in the multi handle.
+ */
+static CURLMcode multi_addmsg(struct Curl_multi *multi,
+ struct Curl_message *msg)
+{
+ if(!Curl_llist_insert_next(multi->msglist, multi->msglist->tail, msg))
+ return CURLM_OUT_OF_MEMORY;
+
+ return CURLM_OK;
+}
+
+/*
+ * multi_freeamsg()
+ *
+ * Callback used by the llist system when a single list entry is destroyed.
+ */
+static void multi_freeamsg(void *a, void *b)
+{
+ (void)a;
+ (void)b;
+}
+
+struct Curl_multi *Curl_multi_handle(int hashsize, /* socket hash */
+ int chashsize) /* connection hash */
+{
+ struct Curl_multi *multi = calloc(1, sizeof(struct Curl_multi));
+
+ if(!multi)
+ return NULL;
+
+ multi->type = CURL_MULTI_HANDLE;
+
+ multi->hostcache = Curl_mk_dnscache();
+ if(!multi->hostcache)
+ goto error;
+
+ multi->sockhash = sh_init(hashsize);
+ if(!multi->sockhash)
+ goto error;
+
+ multi->conn_cache = Curl_conncache_init(chashsize);
+ if(!multi->conn_cache)
+ goto error;
+
+ multi->msglist = Curl_llist_alloc(multi_freeamsg);
+ if(!multi->msglist)
+ goto error;
+
+ /* allocate a new easy handle to use when closing cached connections */
+ multi->closure_handle = curl_easy_init();
+ if(!multi->closure_handle)
+ goto error;
+
+ multi->closure_handle->multi = multi;
+ multi->closure_handle->state.conn_cache = multi->conn_cache;
+
+ multi->max_pipeline_length = 5;
+ return (CURLM *) multi;
+
+ error:
+
+ Curl_hash_destroy(multi->sockhash);
+ multi->sockhash = NULL;
+ Curl_hash_destroy(multi->hostcache);
+ multi->hostcache = NULL;
+ Curl_conncache_destroy(multi->conn_cache);
+ multi->conn_cache = NULL;
+ Curl_close(multi->closure_handle);
+ multi->closure_handle = NULL;
+
+ free(multi);
+ return NULL;
+}
+
+CURLM *curl_multi_init(void)
+{
+ return Curl_multi_handle(CURL_SOCKET_HASH_TABLE_SIZE,
+ CURL_CONNECTION_HASH_SIZE);
+}
+
+CURLMcode curl_multi_add_handle(CURLM *multi_handle,
+ CURL *easy_handle)
+{
+ struct curl_llist *timeoutlist;
+ struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
+ struct SessionHandle *data = (struct SessionHandle *)easy_handle;
+
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* Verify that we got a somewhat good easy handle too */
+ if(!GOOD_EASY_HANDLE(easy_handle))
+ return CURLM_BAD_EASY_HANDLE;
+
+ /* Prevent users from adding same easy handle more than once and prevent
+ adding to more than one multi stack */
+ if(data->multi)
+ return CURLM_ADDED_ALREADY;
+
+ /* Allocate and initialize timeout list for easy handle */
+ timeoutlist = Curl_llist_alloc(multi_freetimeout);
+ if(!timeoutlist)
+ return CURLM_OUT_OF_MEMORY;
+
+ /*
+ * No failure allowed in this function beyond this point. And no
+ * modification of easy nor multi handle allowed before this except for
+ * potential multi's connection cache growing which won't be undone in this
+ * function no matter what.
+ */
+
+ /* Make easy handle use timeout list initialized above */
+ data->state.timeoutlist = timeoutlist;
+ timeoutlist = NULL;
+
+ /* set the easy handle */
+ multistate(data, CURLM_STATE_INIT);
+
+ if((data->set.global_dns_cache) &&
+ (data->dns.hostcachetype != HCACHE_GLOBAL)) {
+ /* global dns cache was requested but still isn't */
+ struct curl_hash *global = Curl_global_host_cache_init();
+ if(global) {
+ /* only do this if the global cache init works */
+ data->dns.hostcache = global;
+ data->dns.hostcachetype = HCACHE_GLOBAL;
+ }
+ }
+ /* for multi interface connections, we share DNS cache automatically if the
+ easy handle's one is currently not set. */
+ else if(!data->dns.hostcache ||
+ (data->dns.hostcachetype == HCACHE_NONE)) {
+ data->dns.hostcache = multi->hostcache;
+ data->dns.hostcachetype = HCACHE_MULTI;
+ }
+
+ /* Point to the multi's connection cache */
+ data->state.conn_cache = multi->conn_cache;
+
+ /* This adds the new entry at the 'end' of the doubly-linked circular
+ list of SessionHandle structs to try and maintain a FIFO queue so
+ the pipelined requests are in order. */
+
+ /* We add this new entry last in the list. */
+
+ data->next = NULL; /* end of the line */
+ if(multi->easyp) {
+ struct SessionHandle *last = multi->easylp;
+ last->next = data;
+ data->prev = last;
+ multi->easylp = data; /* the new last node */
+ }
+ else {
+ /* first node, make both prev and next be NULL! */
+ data->next = NULL;
+ data->prev = NULL;
+ multi->easylp = multi->easyp = data; /* both first and last */
+ }
+
+ /* make the SessionHandle refer back to this multi handle */
+ data->multi = multi_handle;
+
+ /* Set the timeout for this handle to expire really soon so that it will
+ be taken care of even when this handle is added in the midst of operation
+ when only the curl_multi_socket() API is used. During that flow, only
+ sockets that time-out or have actions will be dealt with. Since this
+ handle has no action yet, we make sure it times out to get things to
+ happen. */
+ Curl_expire(data, 1);
+
+ /* increase the node-counter */
+ multi->num_easy++;
+
+ /* increase the alive-counter */
+ multi->num_alive++;
+
+ /* A somewhat crude work-around for a little glitch in update_timer() that
+ happens if the lastcall time is set to the same time when the handle is
+ removed as when the next handle is added, as then the check in
+ update_timer() that prevents calling the application multiple times with
+ the same timer infor will not trigger and then the new handle's timeout
+ will not be notified to the app.
+
+ The work-around is thus simply to clear the 'lastcall' variable to force
+ update_timer() to always trigger a callback to the app when a new easy
+ handle is added */
+ memset(&multi->timer_lastcall, 0, sizeof(multi->timer_lastcall));
+
+ update_timer(multi);
+ return CURLM_OK;
+}
+
+#if 0
+/* Debug-function, used like this:
+ *
+ * Curl_hash_print(multi->sockhash, debug_print_sock_hash);
+ *
+ * Enable the hash print function first by editing hash.c
+ */
+static void debug_print_sock_hash(void *p)
+{
+ struct Curl_sh_entry *sh = (struct Curl_sh_entry *)p;
+
+ fprintf(stderr, " [easy %p/magic %x/socket %d]",
+ (void *)sh->data, sh->data->magic, (int)sh->socket);
+}
+#endif
+
+CURLMcode curl_multi_remove_handle(CURLM *multi_handle,
+ CURL *curl_handle)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *easy = curl_handle;
+ struct SessionHandle *data = easy;
+
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* Verify that we got a somewhat good easy handle too */
+ if(!GOOD_EASY_HANDLE(curl_handle))
+ return CURLM_BAD_EASY_HANDLE;
+
+ /* Prevent users from trying to remove same easy handle more than once */
+ if(!data->multi)
+ return CURLM_OK; /* it is already removed so let's say it is fine! */
+
+ if(easy) {
+ bool premature = (data->mstate < CURLM_STATE_COMPLETED) ? TRUE : FALSE;
+ bool easy_owns_conn = (data->easy_conn &&
+ (data->easy_conn->data == easy)) ?
+ TRUE : FALSE;
+
+ /* If the 'state' is not INIT or COMPLETED, we might need to do something
+ nice to put the easy_handle in a good known state when this returns. */
+ if(premature)
+ /* this handle is "alive" so we need to count down the total number of
+ alive connections when this is removed */
+ multi->num_alive--;
+
+ if(data->easy_conn &&
+ (data->easy_conn->send_pipe->size +
+ data->easy_conn->recv_pipe->size > 1) &&
+ data->mstate > CURLM_STATE_WAITDO &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ /* If the handle is in a pipeline and has started sending off its
+ request but not received its response yet, we need to close
+ connection. */
+ data->easy_conn->bits.close = TRUE;
+ /* Set connection owner so that Curl_done() closes it.
+ We can sefely do this here since connection is killed. */
+ data->easy_conn->data = easy;
+ }
+
+ /* The timer must be shut down before data->multi is set to NULL,
+ else the timenode will remain in the splay tree after
+ curl_easy_cleanup is called. */
+ Curl_expire(data, 0);
+
+ /* destroy the timeout list that is held in the easy handle */
+ if(data->state.timeoutlist) {
+ Curl_llist_destroy(data->state.timeoutlist, NULL);
+ data->state.timeoutlist = NULL;
+ }
+
+ if(data->dns.hostcachetype == HCACHE_MULTI) {
+ /* stop using the multi handle's DNS cache */
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+ if(data->easy_conn) {
+
+ /* we must call Curl_done() here (if we still "own it") so that we don't
+ leave a half-baked one around */
+ if(easy_owns_conn) {
+
+ /* Curl_done() clears the conn->data field to lose the association
+ between the easy handle and the connection
+
+ Note that this ignores the return code simply because there's
+ nothing really useful to do with it anyway! */
+ (void)Curl_done(&data->easy_conn, data->result, premature);
+ }
+ else
+ /* Clear connection pipelines, if Curl_done above was not called */
+ Curl_getoff_all_pipelines(data, data->easy_conn);
+ }
+
+ /* as this was using a shared connection cache we clear the pointer
+ to that since we're not part of that multi handle anymore */
+ data->state.conn_cache = NULL;
+
+ /* change state without using multistate(), only to make singlesocket() do
+ what we want */
+ data->mstate = CURLM_STATE_COMPLETED;
+ singlesocket(multi, easy); /* to let the application know what sockets
+ that vanish with this handle */
+
+ /* Remove the association between the connection and the handle */
+ if(data->easy_conn) {
+ data->easy_conn->data = NULL;
+ data->easy_conn = NULL;
+ }
+
+ data->multi = NULL; /* clear the association to this multi handle */
+
+ {
+ /* make sure there's no pending message in the queue sent from this easy
+ handle */
+ struct curl_llist_element *e;
+
+ for(e = multi->msglist->head; e; e = e->next) {
+ struct Curl_message *msg = e->ptr;
+
+ if(msg->extmsg.easy_handle == easy) {
+ Curl_llist_remove(multi->msglist, e, NULL);
+ /* there can only be one from this specific handle */
+ break;
+ }
+ }
+ }
+
+ /* make the previous node point to our next */
+ if(data->prev)
+ data->prev->next = data->next;
+ else
+ multi->easyp = data->next; /* point to first node */
+
+ /* make our next point to our previous node */
+ if(data->next)
+ data->next->prev = data->prev;
+ else
+ multi->easylp = data->prev; /* point to last node */
+
+ /* NOTE NOTE NOTE
+ We do not touch the easy handle here! */
+
+ multi->num_easy--; /* one less to care about now */
+
+ update_timer(multi);
+ return CURLM_OK;
+ }
+ else
+ return CURLM_BAD_EASY_HANDLE; /* twasn't found */
+}
+
+bool Curl_multi_pipeline_enabled(const struct Curl_multi *multi)
+{
+ return (multi && multi->pipelining_enabled) ? TRUE : FALSE;
+}
+
+void Curl_multi_handlePipeBreak(struct SessionHandle *data)
+{
+ data->easy_conn = NULL;
+}
+
+static int waitconnect_getsock(struct connectdata *conn,
+ curl_socket_t *sock,
+ int numsocks)
+{
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ sock[0] = conn->sock[FIRSTSOCKET];
+
+ /* when we've sent a CONNECT to a proxy, we should rather wait for the
+ socket to become readable to be able to get the response headers */
+ if(conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ return GETSOCK_READSOCK(0);
+
+ return GETSOCK_WRITESOCK(0);
+}
+
+static int domore_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn && conn->handler->domore_getsock)
+ return conn->handler->domore_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+/* returns bitmapped flags for this handle and its sockets */
+static int multi_getsock(struct SessionHandle *data,
+ curl_socket_t *socks, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+ /* If the pipe broke, or if there's no connection left for this easy handle,
+ then we MUST bail out now with no bitmask set. The no connection case can
+ happen when this is called from curl_multi_remove_handle() =>
+ singlesocket() => multi_getsock().
+ */
+ if(data->state.pipe_broke || !data->easy_conn)
+ return 0;
+
+ if(data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_COMPLETED) {
+ /* Set up ownership correctly */
+ data->easy_conn->data = data;
+ }
+
+ switch(data->mstate) {
+ default:
+#if 0 /* switch back on these cases to get the compiler to check for all enums
+ to be present */
+ case CURLM_STATE_TOOFAST: /* returns 0, so will not select. */
+ case CURLM_STATE_COMPLETED:
+ case CURLM_STATE_MSGSENT:
+ case CURLM_STATE_INIT:
+ case CURLM_STATE_CONNECT:
+ case CURLM_STATE_WAITDO:
+ case CURLM_STATE_DONE:
+ case CURLM_STATE_LAST:
+ /* this will get called with CURLM_STATE_COMPLETED when a handle is
+ removed */
+#endif
+ return 0;
+
+ case CURLM_STATE_WAITRESOLVE:
+ return Curl_resolver_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_PROTOCONNECT:
+ return Curl_protocol_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO:
+ case CURLM_STATE_DOING:
+ return Curl_doing_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_WAITPROXYCONNECT:
+ case CURLM_STATE_WAITCONNECT:
+ return waitconnect_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO_MORE:
+ return domore_getsock(data->easy_conn, socks, numsocks);
+
+ case CURLM_STATE_DO_DONE: /* since is set after DO is completed, we switch
+ to waiting for the same as the *PERFORM
+ states */
+ case CURLM_STATE_PERFORM:
+ case CURLM_STATE_WAITPERFORM:
+ return Curl_single_getsock(data->easy_conn, socks, numsocks);
+ }
+
+}
+
+CURLMcode curl_multi_fdset(CURLM *multi_handle,
+ fd_set *read_fd_set, fd_set *write_fd_set,
+ fd_set *exc_fd_set, int *max_fd)
+{
+ /* Scan through all the easy handles to get the file descriptors set.
+ Some easy handles may not have connected to the remote host yet,
+ and then we must make sure that is done. */
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data;
+ int this_max_fd=-1;
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+ int i;
+ (void)exc_fd_set; /* not used */
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if((bitmap & GETSOCK_READSOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ FD_SET(sockbunch[i], read_fd_set);
+ s = sockbunch[i];
+ }
+ if((bitmap & GETSOCK_WRITESOCK(i)) && VALID_SOCK((sockbunch[i]))) {
+ FD_SET(sockbunch[i], write_fd_set);
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD)
+ /* this socket is unused, break out of loop */
+ break;
+ else {
+ if((int)s > this_max_fd)
+ this_max_fd = (int)s;
+ }
+ }
+
+ data = data->next; /* check next handle */
+ }
+
+ *max_fd = this_max_fd;
+
+ return CURLM_OK;
+}
+
+CURLMcode curl_multi_wait(CURLM *multi_handle,
+ struct curl_waitfd extra_fds[],
+ unsigned int extra_nfds,
+ int timeout_ms,
+ int *ret)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data;
+ curl_socket_t sockbunch[MAX_SOCKSPEREASYHANDLE];
+ int bitmap;
+ unsigned int i;
+ unsigned int nfds = 0;
+ unsigned int curlfds;
+ struct pollfd *ufds = NULL;
+ long timeout_internal;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ /* If the internally desired timeout is actually shorter than requested from
+ the outside, then use the shorter time! But only if the internal timer
+ is actually larger than 0! */
+ (void)multi_timeout(multi, &timeout_internal);
+ if((timeout_internal > 0) && (timeout_internal < (long)timeout_ms))
+ timeout_ms = (int)timeout_internal;
+
+ /* Count up how many fds we have from the multi handle */
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if(bitmap & GETSOCK_READSOCK(i)) {
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(bitmap & GETSOCK_WRITESOCK(i)) {
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD) {
+ break;
+ }
+ }
+
+ data = data->next; /* check next handle */
+ }
+
+ curlfds = nfds; /* number of internal file descriptors */
+ nfds += extra_nfds; /* add the externally provided ones */
+
+ if(nfds) {
+ ufds = malloc(nfds * sizeof(struct pollfd));
+ if(!ufds)
+ return CURLM_OUT_OF_MEMORY;
+ }
+ nfds = 0;
+
+ /* only do the second loop if we found descriptors in the first stage run
+ above */
+
+ if(curlfds) {
+ /* Add the curl handles to our pollfds first */
+ data=multi->easyp;
+ while(data) {
+ bitmap = multi_getsock(data, sockbunch, MAX_SOCKSPEREASYHANDLE);
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++) {
+ curl_socket_t s = CURL_SOCKET_BAD;
+
+ if(bitmap & GETSOCK_READSOCK(i)) {
+ ufds[nfds].fd = sockbunch[i];
+ ufds[nfds].events = POLLIN;
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(bitmap & GETSOCK_WRITESOCK(i)) {
+ ufds[nfds].fd = sockbunch[i];
+ ufds[nfds].events = POLLOUT;
+ ++nfds;
+ s = sockbunch[i];
+ }
+ if(s == CURL_SOCKET_BAD) {
+ break;
+ }
+ }
+
+ data = data->next; /* check next handle */
+ }
+ }
+
+ /* Add external file descriptions from poll-like struct curl_waitfd */
+ for(i = 0; i < extra_nfds; i++) {
+ ufds[nfds].fd = extra_fds[i].fd;
+ ufds[nfds].events = 0;
+ if(extra_fds[i].events & CURL_WAIT_POLLIN)
+ ufds[nfds].events |= POLLIN;
+ if(extra_fds[i].events & CURL_WAIT_POLLPRI)
+ ufds[nfds].events |= POLLPRI;
+ if(extra_fds[i].events & CURL_WAIT_POLLOUT)
+ ufds[nfds].events |= POLLOUT;
+ ++nfds;
+ }
+
+ if(nfds) {
+ /* wait... */
+ i = Curl_poll(ufds, nfds, timeout_ms);
+
+ if(i) {
+ unsigned int j;
+ /* copy revents results from the poll to the curl_multi_wait poll
+ struct, the bit values of the actual underlying poll() implementation
+ may not be the same as the ones in the public libcurl API! */
+ for(j = 0; j < extra_nfds; j++) {
+ unsigned short mask = 0;
+ unsigned r = ufds[curlfds + j].revents;
+
+ if(r & POLLIN)
+ mask |= CURL_WAIT_POLLIN;
+ if(r & POLLOUT)
+ mask |= CURL_WAIT_POLLOUT;
+ if(r & POLLPRI)
+ mask |= CURL_WAIT_POLLPRI;
+
+ extra_fds[j].revents = mask;
+ }
+ }
+ }
+ else
+ i = 0;
+
+ Curl_safefree(ufds);
+ if(ret)
+ *ret = i;
+ return CURLM_OK;
+}
+
+static CURLMcode multi_runsingle(struct Curl_multi *multi,
+ struct timeval now,
+ struct SessionHandle *data)
+{
+ struct Curl_message *msg = NULL;
+ bool connected;
+ bool async;
+ bool protocol_connect = FALSE;
+ bool dophase_done = FALSE;
+ bool done = FALSE;
+ CURLMcode result = CURLM_OK;
+ struct SingleRequest *k;
+ long timeout_ms;
+ int control;
+
+ if(!GOOD_EASY_HANDLE(data))
+ return CURLM_BAD_EASY_HANDLE;
+
+ do {
+ /* this is a single-iteration do-while loop just to allow a
+ break to skip to the end of it */
+ bool disconnect_conn = FALSE;
+
+ /* Handle the case when the pipe breaks, i.e., the connection
+ we're using gets cleaned up and we're left with nothing. */
+ if(data->state.pipe_broke) {
+ infof(data, "Pipe broke: handle 0x%p, url = %s\n",
+ (void *)data, data->state.path);
+
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ /* Head back to the CONNECT state */
+ multistate(data, CURLM_STATE_CONNECT);
+ result = CURLM_CALL_MULTI_PERFORM;
+ data->result = CURLE_OK;
+ }
+
+ data->state.pipe_broke = FALSE;
+ data->easy_conn = NULL;
+ break;
+ }
+
+ if(!data->easy_conn &&
+ data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_DONE) {
+ /* In all these states, the code will blindly access 'data->easy_conn'
+ so this is precaution that it isn't NULL. And it silences static
+ analyzers. */
+ failf(data, "In state %d with no easy_conn, bail out!\n", data->mstate);
+ return CURLM_INTERNAL_ERROR;
+ }
+
+ if(data->easy_conn && data->mstate > CURLM_STATE_CONNECT &&
+ data->mstate < CURLM_STATE_COMPLETED)
+ /* Make sure we set the connection's current owner */
+ data->easy_conn->data = data;
+
+ if(data->easy_conn &&
+ (data->mstate >= CURLM_STATE_CONNECT) &&
+ (data->mstate < CURLM_STATE_COMPLETED)) {
+ /* we need to wait for the connect state as only then is the start time
+ stored, but we must not check already completed handles */
+
+ timeout_ms = Curl_timeleft(data, &now,
+ (data->mstate <= CURLM_STATE_WAITDO)?
+ TRUE:FALSE);
+
+ if(timeout_ms < 0) {
+ /* Handle timed out */
+ if(data->mstate == CURLM_STATE_WAITRESOLVE)
+ failf(data, "Resolving timed out after %ld milliseconds",
+ Curl_tvdiff(now, data->progress.t_startsingle));
+ else if(data->mstate == CURLM_STATE_WAITCONNECT)
+ failf(data, "Connection timed out after %ld milliseconds",
+ Curl_tvdiff(now, data->progress.t_startsingle));
+ else {
+ k = &data->req;
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
+ Curl_tvdiff(now, data->progress.t_startsingle), k->bytecount,
+ k->size);
+ }
+
+ /* Force the connection closed because the server could continue to
+ send us stuff at any time. (The disconnect_conn logic used below
+ doesn't work at this point). */
+ data->easy_conn->bits.close = TRUE;
+ data->result = CURLE_OPERATION_TIMEDOUT;
+ multistate(data, CURLM_STATE_COMPLETED);
+ break;
+ }
+ }
+
+ switch(data->mstate) {
+ case CURLM_STATE_INIT:
+ /* init this transfer. */
+ data->result=Curl_pretransfer(data);
+
+ if(CURLE_OK == data->result) {
+ /* after init, go CONNECT */
+ multistate(data, CURLM_STATE_CONNECT);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_CONNECT_PEND:
+ /* We will stay here until there is a connection available. Then
+ we try again in the CURLM_STATE_CONNECT state. */
+ break;
+
+ case CURLM_STATE_CONNECT:
+ /* Connect. We want to get a connection identifier filled in. */
+ Curl_pgrsTime(data, TIMER_STARTSINGLE);
+ data->result = Curl_connect(data, &data->easy_conn,
+ &async, &protocol_connect);
+ if(CURLE_NO_CONNECTION_AVAILABLE == data->result) {
+ /* There was no connection available. We will go to the pending
+ state and wait for an available connection. */
+ multistate(data, CURLM_STATE_CONNECT_PEND);
+ data->result = CURLE_OK;
+ break;
+ }
+
+ if(CURLE_OK == data->result) {
+ /* Add this handle to the send or pend pipeline */
+ data->result = Curl_add_handle_to_pipeline(data, data->easy_conn);
+ if(CURLE_OK != data->result)
+ disconnect_conn = TRUE;
+ else {
+ if(async)
+ /* We're now waiting for an asynchronous name lookup */
+ multistate(data, CURLM_STATE_WAITRESOLVE);
+ else {
+ /* after the connect has been sent off, go WAITCONNECT unless the
+ protocol connect is already done and we can go directly to
+ WAITDO or DO! */
+ result = CURLM_CALL_MULTI_PERFORM;
+
+ if(protocol_connect)
+ multistate(data, multi->pipelining_enabled?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ else {
+#ifndef CURL_DISABLE_HTTP
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
+#endif
+ multistate(data, CURLM_STATE_WAITCONNECT);
+ }
+ }
+ }
+ }
+ break;
+
+ case CURLM_STATE_WAITRESOLVE:
+ /* awaiting an asynch name resolve to complete */
+ {
+ struct Curl_dns_entry *dns = NULL;
+
+ /* check if we have the name resolved by now */
+ data->result = Curl_resolver_is_resolved(data->easy_conn, &dns);
+
+ /* Update sockets here, because the socket(s) may have been
+ closed and the application thus needs to be told, even if it
+ is likely that the same socket(s) will again be used further
+ down. If the name has not yet been resolved, it is likely
+ that new sockets have been opened in an attempt to contact
+ another resolver. */
+ singlesocket(multi, data);
+
+ if(dns) {
+ /* Perform the next step in the connection phase, and then move on
+ to the WAITCONNECT state */
+ data->result = Curl_async_resolved(data->easy_conn,
+ &protocol_connect);
+
+ if(CURLE_OK != data->result)
+ /* if Curl_async_resolved() returns failure, the connection struct
+ is already freed and gone */
+ data->easy_conn = NULL; /* no more connection */
+ else {
+ /* call again please so that we get the next socket setup */
+ result = CURLM_CALL_MULTI_PERFORM;
+ if(protocol_connect)
+ multistate(data, multi->pipelining_enabled?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ else {
+#ifndef CURL_DISABLE_HTTP
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
+#endif
+ multistate(data, CURLM_STATE_WAITCONNECT);
+ }
+ }
+ }
+
+ if(CURLE_OK != data->result) {
+ /* failure detected */
+ disconnect_conn = TRUE;
+ break;
+ }
+ }
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLM_STATE_WAITPROXYCONNECT:
+ /* this is HTTP-specific, but sending CONNECT to a proxy is HTTP... */
+ data->result = Curl_http_connect(data->easy_conn, &protocol_connect);
+
+ if(data->easy_conn->bits.proxy_connect_closed) {
+ /* reset the error buffer */
+ if(data->set.errorbuffer)
+ data->set.errorbuffer[0] = '\0';
+ data->state.errorbuf = FALSE;
+
+ data->result = CURLE_OK;
+ result = CURLM_CALL_MULTI_PERFORM;
+ multistate(data, CURLM_STATE_CONNECT);
+ }
+ else if(CURLE_OK == data->result) {
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_COMPLETE)
+ multistate(data, CURLM_STATE_WAITCONNECT);
+ }
+ break;
+#endif
+
+ case CURLM_STATE_WAITCONNECT:
+ /* awaiting a completion of an asynch connect */
+ data->result = Curl_is_connected(data->easy_conn,
+ FIRSTSOCKET,
+ &connected);
+ if(connected) {
+
+ if(!data->result)
+ /* if everything is still fine we do the protocol-specific connect
+ setup */
+ data->result = Curl_protocol_connect(data->easy_conn,
+ &protocol_connect);
+ }
+
+ if(CURLE_OK != data->result) {
+ /* failure detected */
+ /* Just break, the cleaning up is handled all in one place */
+ disconnect_conn = TRUE;
+ break;
+ }
+
+ if(connected) {
+ if(!protocol_connect) {
+ /* We have a TCP connection, but 'protocol_connect' may be false
+ and then we continue to 'STATE_PROTOCONNECT'. If protocol
+ connect is TRUE, we move on to STATE_DO.
+ BUT if we are using a proxy we must change to WAITPROXYCONNECT
+ */
+#ifndef CURL_DISABLE_HTTP
+ if(data->easy_conn->tunnel_state[FIRSTSOCKET] == TUNNEL_CONNECT)
+ multistate(data, CURLM_STATE_WAITPROXYCONNECT);
+ else
+#endif
+ multistate(data, CURLM_STATE_PROTOCONNECT);
+
+ }
+ else
+ /* after the connect has completed, go WAITDO or DO */
+ multistate(data, multi->pipelining_enabled?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_PROTOCONNECT:
+ /* protocol-specific connect phase */
+ data->result = Curl_protocol_connecting(data->easy_conn,
+ &protocol_connect);
+ if((data->result == CURLE_OK) && protocol_connect) {
+ /* after the connect has completed, go WAITDO or DO */
+ multistate(data, multi->pipelining_enabled?
+ CURLM_STATE_WAITDO:CURLM_STATE_DO);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ else if(data->result) {
+ /* failure detected */
+ Curl_posttransfer(data);
+ Curl_done(&data->easy_conn, data->result, TRUE);
+ disconnect_conn = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_WAITDO:
+ /* Wait for our turn to DO when we're pipelining requests */
+#ifdef DEBUGBUILD
+ infof(data, "WAITDO: Conn %ld send pipe %zu inuse %s athead %s\n",
+ data->easy_conn->connection_id,
+ data->easy_conn->send_pipe->size,
+ data->easy_conn->writechannel_inuse?"TRUE":"FALSE",
+ isHandleAtHead(data,
+ data->easy_conn->send_pipe)?"TRUE":"FALSE");
+#endif
+ if(!data->easy_conn->writechannel_inuse &&
+ isHandleAtHead(data,
+ data->easy_conn->send_pipe)) {
+ /* Grab the channel */
+ data->easy_conn->writechannel_inuse = TRUE;
+ multistate(data, CURLM_STATE_DO);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ break;
+
+ case CURLM_STATE_DO:
+ if(data->set.connect_only) {
+ /* keep connection open for application to use the socket */
+ data->easy_conn->bits.close = FALSE;
+ multistate(data, CURLM_STATE_DONE);
+ data->result = CURLE_OK;
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ else {
+ /* Perform the protocol's DO action */
+ data->result = Curl_do(&data->easy_conn, &dophase_done);
+
+ /* When Curl_do() returns failure, data->easy_conn might be NULL! */
+
+ if(CURLE_OK == data->result) {
+ if(!dophase_done) {
+ /* some steps needed for wildcard matching */
+ if(data->set.wildcardmatch) {
+ struct WildcardData *wc = &data->wildcard;
+ if(wc->state == CURLWC_DONE || wc->state == CURLWC_SKIP) {
+ /* skip some states if it is important */
+ Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+ multistate(data, CURLM_STATE_DONE);
+ result = CURLM_CALL_MULTI_PERFORM;
+ break;
+ }
+ }
+ /* DO was not completed in one function call, we must continue
+ DOING... */
+ multistate(data, CURLM_STATE_DOING);
+ result = CURLM_OK;
+ }
+
+ /* after DO, go DO_DONE... or DO_MORE */
+ else if(data->easy_conn->bits.do_more) {
+ /* we're supposed to do more, but we need to sit down, relax
+ and wait a little while first */
+ multistate(data, CURLM_STATE_DO_MORE);
+ result = CURLM_OK;
+ }
+ else {
+ /* we're done with the DO, now DO_DONE */
+ multistate(data, CURLM_STATE_DO_DONE);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ else if((CURLE_SEND_ERROR == data->result) &&
+ data->easy_conn->bits.reuse) {
+ /*
+ * In this situation, a connection that we were trying to use
+ * may have unexpectedly died. If possible, send the connection
+ * back to the CONNECT phase so we can try again.
+ */
+ char *newurl = NULL;
+ followtype follow=FOLLOW_NONE;
+ CURLcode drc;
+ bool retry = FALSE;
+
+ drc = Curl_retry_request(data->easy_conn, &newurl);
+ if(drc) {
+ /* a failure here pretty much implies an out of memory */
+ data->result = drc;
+ disconnect_conn = TRUE;
+ }
+ else
+ retry = (newurl)?TRUE:FALSE;
+
+ Curl_posttransfer(data);
+ drc = Curl_done(&data->easy_conn, data->result, FALSE);
+
+ /* When set to retry the connection, we must to go back to
+ * the CONNECT state */
+ if(retry) {
+ if((drc == CURLE_OK) || (drc == CURLE_SEND_ERROR)) {
+ follow = FOLLOW_RETRY;
+ drc = Curl_follow(data, newurl, follow);
+ if(drc == CURLE_OK) {
+ multistate(data, CURLM_STATE_CONNECT);
+ result = CURLM_CALL_MULTI_PERFORM;
+ data->result = CURLE_OK;
+ }
+ else {
+ /* Follow failed */
+ data->result = drc;
+ free(newurl);
+ }
+ }
+ else {
+ /* done didn't return OK or SEND_ERROR */
+ data->result = drc;
+ free(newurl);
+ }
+ }
+ else {
+ /* Have error handler disconnect conn if we can't retry */
+ disconnect_conn = TRUE;
+ }
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ if(data->easy_conn)
+ Curl_done(&data->easy_conn, data->result, FALSE);
+ disconnect_conn = TRUE;
+ }
+ }
+ break;
+
+ case CURLM_STATE_DOING:
+ /* we continue DOING until the DO phase is complete */
+ data->result = Curl_protocol_doing(data->easy_conn,
+ &dophase_done);
+ if(CURLE_OK == data->result) {
+ if(dophase_done) {
+ /* after DO, go DO_DONE or DO_MORE */
+ multistate(data, data->easy_conn->bits.do_more?
+ CURLM_STATE_DO_MORE:
+ CURLM_STATE_DO_DONE);
+ result = CURLM_CALL_MULTI_PERFORM;
+ } /* dophase_done */
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ Curl_done(&data->easy_conn, data->result, FALSE);
+ disconnect_conn = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_DO_MORE:
+ /*
+ * When we are connected, DO MORE and then go DO_DONE
+ */
+ data->result = Curl_do_more(data->easy_conn, &control);
+
+ /* No need to remove this handle from the send pipeline here since that
+ is done in Curl_done() */
+ if(CURLE_OK == data->result) {
+ if(control) {
+ /* if positive, advance to DO_DONE
+ if negative, go back to DOING */
+ multistate(data, control==1?
+ CURLM_STATE_DO_DONE:
+ CURLM_STATE_DOING);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ else
+ /* stay in DO_MORE */
+ result = CURLM_OK;
+ }
+ else {
+ /* failure detected */
+ Curl_posttransfer(data);
+ Curl_done(&data->easy_conn, data->result, FALSE);
+ disconnect_conn = TRUE;
+ }
+ break;
+
+ case CURLM_STATE_DO_DONE:
+ /* Move ourselves from the send to recv pipeline */
+ Curl_move_handle_from_send_to_recv_pipe(data, data->easy_conn);
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+ multistate(data, CURLM_STATE_WAITPERFORM);
+ result = CURLM_CALL_MULTI_PERFORM;
+ break;
+
+ case CURLM_STATE_WAITPERFORM:
+ /* Wait for our turn to PERFORM */
+ if(!data->easy_conn->readchannel_inuse &&
+ isHandleAtHead(data,
+ data->easy_conn->recv_pipe)) {
+ /* Grab the channel */
+ data->easy_conn->readchannel_inuse = TRUE;
+ multistate(data, CURLM_STATE_PERFORM);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+#ifdef DEBUGBUILD
+ else {
+ infof(data, "WAITPERFORM: Conn %ld recv pipe %zu inuse %s athead %s\n",
+ data->easy_conn->connection_id,
+ data->easy_conn->recv_pipe->size,
+ data->easy_conn->readchannel_inuse?"TRUE":"FALSE",
+ isHandleAtHead(data,
+ data->easy_conn->recv_pipe)?"TRUE":"FALSE");
+ }
+#endif
+ break;
+
+ case CURLM_STATE_TOOFAST: /* limit-rate exceeded in either direction */
+ /* if both rates are within spec, resume transfer */
+ if(Curl_pgrsUpdate(data->easy_conn))
+ data->result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ data->result = Curl_speedcheck(data, now);
+
+ if(( (data->set.max_send_speed == 0) ||
+ (data->progress.ulspeed < data->set.max_send_speed )) &&
+ ( (data->set.max_recv_speed == 0) ||
+ (data->progress.dlspeed < data->set.max_recv_speed)))
+ multistate(data, CURLM_STATE_PERFORM);
+ break;
+
+ case CURLM_STATE_PERFORM:
+ {
+ char *newurl = NULL;
+ bool retry = FALSE;
+
+ /* check if over send speed */
+ if((data->set.max_send_speed > 0) &&
+ (data->progress.ulspeed > data->set.max_send_speed)) {
+ int buffersize;
+
+ multistate(data, CURLM_STATE_TOOFAST);
+
+ /* calculate upload rate-limitation timeout. */
+ buffersize = (int)(data->set.buffer_size ?
+ data->set.buffer_size : BUFSIZE);
+ timeout_ms = Curl_sleep_time(data->set.max_send_speed,
+ data->progress.ulspeed, buffersize);
+ Curl_expire(data, timeout_ms);
+ break;
+ }
+
+ /* check if over recv speed */
+ if((data->set.max_recv_speed > 0) &&
+ (data->progress.dlspeed > data->set.max_recv_speed)) {
+ int buffersize;
+
+ multistate(data, CURLM_STATE_TOOFAST);
+
+ /* Calculate download rate-limitation timeout. */
+ buffersize = (int)(data->set.buffer_size ?
+ data->set.buffer_size : BUFSIZE);
+ timeout_ms = Curl_sleep_time(data->set.max_recv_speed,
+ data->progress.dlspeed, buffersize);
+ Curl_expire(data, timeout_ms);
+ break;
+ }
+
+ /* read/write data if it is ready to do so */
+ data->result = Curl_readwrite(data->easy_conn, &done);
+
+ k = &data->req;
+
+ if(!(k->keepon & KEEP_RECV)) {
+ /* We're done receiving */
+ data->easy_conn->readchannel_inuse = FALSE;
+ }
+
+ if(!(k->keepon & KEEP_SEND)) {
+ /* We're done sending */
+ data->easy_conn->writechannel_inuse = FALSE;
+ }
+
+ if(done || (data->result == CURLE_RECV_ERROR)) {
+ /* If CURLE_RECV_ERROR happens early enough, we assume it was a race
+ * condition and the server closed the re-used connection exactly when
+ * we wanted to use it, so figure out if that is indeed the case.
+ */
+ CURLcode ret = Curl_retry_request(data->easy_conn, &newurl);
+ if(!ret)
+ retry = (newurl)?TRUE:FALSE;
+
+ if(retry) {
+ /* if we are to retry, set the result to OK and consider the
+ request as done */
+ data->result = CURLE_OK;
+ done = TRUE;
+ }
+ }
+
+ if(data->result) {
+ /*
+ * The transfer phase returned error, we mark the connection to get
+ * closed to prevent being re-used. This is because we can't possibly
+ * know if the connection is in a good shape or not now. Unless it is
+ * a protocol which uses two "channels" like FTP, as then the error
+ * happened in the data connection.
+ */
+
+ if(!(data->easy_conn->handler->flags & PROTOPT_DUAL))
+ data->easy_conn->bits.close = TRUE;
+
+ Curl_posttransfer(data);
+ Curl_done(&data->easy_conn, data->result, FALSE);
+ }
+ else if(done) {
+ followtype follow=FOLLOW_NONE;
+
+ /* call this even if the readwrite function returned error */
+ Curl_posttransfer(data);
+
+ /* we're no longer receiving */
+ Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
+
+ /* expire the new receiving pipeline head */
+ if(data->easy_conn->recv_pipe->head)
+ Curl_expire(data->easy_conn->recv_pipe->head->ptr, 1);
+
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ /* When we follow redirects or is set to retry the connection, we must
+ to go back to the CONNECT state */
+ if(data->req.newurl || retry) {
+ if(!retry) {
+ /* if the URL is a follow-location and not just a retried request
+ then figure out the URL here */
+ newurl = data->req.newurl;
+ data->req.newurl = NULL;
+ follow = FOLLOW_REDIR;
+ }
+ else
+ follow = FOLLOW_RETRY;
+ data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+ if(CURLE_OK == data->result) {
+ data->result = Curl_follow(data, newurl, follow);
+ if(CURLE_OK == data->result) {
+ multistate(data, CURLM_STATE_CONNECT);
+ result = CURLM_CALL_MULTI_PERFORM;
+ newurl = NULL; /* handed over the memory ownership to
+ Curl_follow(), make sure we don't free() it
+ here */
+ }
+ }
+ }
+ else {
+ /* after the transfer is done, go DONE */
+
+ /* but first check to see if we got a location info even though we're
+ not following redirects */
+ if(data->req.location) {
+ if(newurl)
+ free(newurl);
+ newurl = data->req.location;
+ data->req.location = NULL;
+ data->result = Curl_follow(data, newurl, FOLLOW_FAKE);
+ if(CURLE_OK == data->result)
+ newurl = NULL; /* allocation was handed over Curl_follow() */
+ else
+ disconnect_conn = TRUE;
+ }
+
+ multistate(data, CURLM_STATE_DONE);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+
+ if(newurl)
+ free(newurl);
+ break;
+ }
+
+ case CURLM_STATE_DONE:
+ /* this state is highly transient, so run another loop after this */
+ result = CURLM_CALL_MULTI_PERFORM;
+
+ if(data->easy_conn) {
+ /* Remove ourselves from the receive pipeline, if we are there. */
+ Curl_removeHandleFromPipeline(data, data->easy_conn->recv_pipe);
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ /* post-transfer command */
+ data->result = Curl_done(&data->easy_conn, CURLE_OK, FALSE);
+ /*
+ * If there are other handles on the pipeline, Curl_done won't set
+ * easy_conn to NULL. In such a case, curl_multi_remove_handle() can
+ * access free'd data, if the connection is free'd and the handle
+ * removed before we perform the processing in CURLM_STATE_COMPLETED
+ */
+ if(data->easy_conn)
+ data->easy_conn = NULL;
+ }
+
+ if(data->set.wildcardmatch) {
+ if(data->wildcard.state != CURLWC_DONE) {
+ /* if a wildcard is set and we are not ending -> lets start again
+ with CURLM_STATE_INIT */
+ multistate(data, CURLM_STATE_INIT);
+ break;
+ }
+ }
+
+ /* after we have DONE what we're supposed to do, go COMPLETED, and
+ it doesn't matter what the Curl_done() returned! */
+ multistate(data, CURLM_STATE_COMPLETED);
+ break;
+
+ case CURLM_STATE_COMPLETED:
+ /* this is a completed transfer, it is likely to still be connected */
+
+ /* This node should be delinked from the list now and we should post
+ an information message that we are complete. */
+
+ /* Important: reset the conn pointer so that we don't point to memory
+ that could be freed anytime */
+ data->easy_conn = NULL;
+
+ Curl_expire(data, 0); /* stop all timers */
+ break;
+
+ case CURLM_STATE_MSGSENT:
+ return CURLM_OK; /* do nothing */
+
+ default:
+ return CURLM_INTERNAL_ERROR;
+ }
+
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ if(CURLE_OK != data->result) {
+ /*
+ * If an error was returned, and we aren't in completed state now,
+ * then we go to completed and consider this transfer aborted.
+ */
+
+ /* NOTE: no attempt to disconnect connections must be made
+ in the case blocks above - cleanup happens only here */
+
+ data->state.pipe_broke = FALSE;
+
+ if(data->easy_conn) {
+ /* if this has a connection, unsubscribe from the pipelines */
+ data->easy_conn->writechannel_inuse = FALSE;
+ data->easy_conn->readchannel_inuse = FALSE;
+ Curl_removeHandleFromPipeline(data,
+ data->easy_conn->send_pipe);
+ Curl_removeHandleFromPipeline(data,
+ data->easy_conn->recv_pipe);
+ /* Check if we can move pending requests to send pipe */
+ Curl_multi_process_pending_handles(multi);
+
+ if(disconnect_conn) {
+ /* disconnect properly */
+ Curl_disconnect(data->easy_conn, /* dead_connection */ FALSE);
+
+ /* This is where we make sure that the easy_conn pointer is reset.
+ We don't have to do this in every case block above where a
+ failure is detected */
+ data->easy_conn = NULL;
+ }
+ }
+ else if(data->mstate == CURLM_STATE_CONNECT) {
+ /* Curl_connect() failed */
+ (void)Curl_posttransfer(data);
+ }
+
+ multistate(data, CURLM_STATE_COMPLETED);
+ }
+ /* if there's still a connection to use, call the progress function */
+ else if(data->easy_conn && Curl_pgrsUpdate(data->easy_conn)) {
+ /* aborted due to progress callback return code must close the
+ connection */
+ data->easy_conn->bits.close = TRUE;
+
+ /* if not yet in DONE state, go there, otherwise COMPLETED */
+ multistate(data, (data->mstate < CURLM_STATE_DONE)?
+ CURLM_STATE_DONE: CURLM_STATE_COMPLETED);
+ result = CURLM_CALL_MULTI_PERFORM;
+ }
+ }
+ } WHILE_FALSE; /* just to break out from! */
+
+ if(CURLM_STATE_COMPLETED == data->mstate) {
+ /* now fill in the Curl_message with this info */
+ msg = &data->msg;
+
+ msg->extmsg.msg = CURLMSG_DONE;
+ msg->extmsg.easy_handle = data;
+ msg->extmsg.data.result = data->result;
+
+ result = multi_addmsg(multi, msg);
+
+ multistate(data, CURLM_STATE_MSGSENT);
+ }
+
+ return result;
+}
+
+
+CURLMcode curl_multi_perform(CURLM *multi_handle, int *running_handles)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data;
+ CURLMcode returncode=CURLM_OK;
+ struct Curl_tree *t;
+ struct timeval now = Curl_tvnow();
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ data=multi->easyp;
+ while(data) {
+ CURLMcode result;
+ struct WildcardData *wc = &data->wildcard;
+
+ if(data->set.wildcardmatch) {
+ if(!wc->filelist) {
+ CURLcode ret = Curl_wildcard_init(wc); /* init wildcard structures */
+ if(ret)
+ return CURLM_OUT_OF_MEMORY;
+ }
+ }
+
+ do
+ result = multi_runsingle(multi, now, data);
+ while(CURLM_CALL_MULTI_PERFORM == result);
+
+ if(data->set.wildcardmatch) {
+ /* destruct wildcard structures if it is needed */
+ if(wc->state == CURLWC_DONE || result)
+ Curl_wildcard_dtor(wc);
+ }
+
+ if(result)
+ returncode = result;
+
+ data = data->next; /* operate on next handle */
+ }
+
+ /*
+ * Simply remove all expired timers from the splay since handles are dealt
+ * with unconditionally by this function and curl_multi_timeout() requires
+ * that already passed/handled expire times are removed from the splay.
+ *
+ * It is important that the 'now' value is set at the entry of this function
+ * and not for the current time as it may have ticked a little while since
+ * then and then we risk this loop to remove timers that actually have not
+ * been handled!
+ */
+ do {
+ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+ if(t)
+ /* the removed may have another timeout in queue */
+ (void)add_next_timeout(now, multi, t->payload);
+
+ } while(t);
+
+ *running_handles = multi->num_alive;
+
+ if(CURLM_OK >= returncode)
+ update_timer(multi);
+
+ return returncode;
+}
+
+static void close_all_connections(struct Curl_multi *multi)
+{
+ struct connectdata *conn;
+
+ conn = Curl_conncache_find_first_connection(multi->conn_cache);
+ while(conn) {
+ conn->data = multi->closure_handle;
+
+ /* This will remove the connection from the cache */
+ (void)Curl_disconnect(conn, FALSE);
+
+ conn = Curl_conncache_find_first_connection(multi->conn_cache);
+ }
+}
+
+CURLMcode curl_multi_cleanup(CURLM *multi_handle)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data;
+ struct SessionHandle *nextdata;
+
+ if(GOOD_MULTI_HANDLE(multi)) {
+ multi->type = 0; /* not good anymore */
+
+ /* Close all the connections in the connection cache */
+ close_all_connections(multi);
+
+ if(multi->closure_handle) {
+ multi->closure_handle->dns.hostcache = multi->hostcache;
+ Curl_hostcache_clean(multi->closure_handle,
+ multi->closure_handle->dns.hostcache);
+
+ Curl_close(multi->closure_handle);
+ multi->closure_handle = NULL;
+ }
+
+ Curl_hash_destroy(multi->sockhash);
+ multi->sockhash = NULL;
+
+ Curl_conncache_destroy(multi->conn_cache);
+ multi->conn_cache = NULL;
+
+ /* remove the pending list of messages */
+ Curl_llist_destroy(multi->msglist, NULL);
+ multi->msglist = NULL;
+
+ /* remove all easy handles */
+ data = multi->easyp;
+ while(data) {
+ nextdata=data->next;
+ if(data->dns.hostcachetype == HCACHE_MULTI) {
+ /* clear out the usage of the shared DNS cache */
+ Curl_hostcache_clean(data, data->dns.hostcache);
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+ /* Clear the pointer to the connection cache */
+ data->state.conn_cache = NULL;
+ data->multi = NULL; /* clear the association */
+
+ data = nextdata;
+ }
+
+ Curl_hash_destroy(multi->hostcache);
+ multi->hostcache = NULL;
+
+ /* Free the blacklists by setting them to NULL */
+ Curl_pipeline_set_site_blacklist(NULL, &multi->pipelining_site_bl);
+ Curl_pipeline_set_server_blacklist(NULL, &multi->pipelining_server_bl);
+
+ free(multi);
+
+ return CURLM_OK;
+ }
+ else
+ return CURLM_BAD_HANDLE;
+}
+
+/*
+ * curl_multi_info_read()
+ *
+ * This function is the primary way for a multi/multi_socket application to
+ * figure out if a transfer has ended. We MUST make this function as fast as
+ * possible as it will be polled frequently and we MUST NOT scan any lists in
+ * here to figure out things. We must scale fine to thousands of handles and
+ * beyond. The current design is fully O(1).
+ */
+
+CURLMsg *curl_multi_info_read(CURLM *multi_handle, int *msgs_in_queue)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct Curl_message *msg;
+
+ *msgs_in_queue = 0; /* default to none */
+
+ if(GOOD_MULTI_HANDLE(multi) && Curl_llist_count(multi->msglist)) {
+ /* there is one or more messages in the list */
+ struct curl_llist_element *e;
+
+ /* extract the head of the list to return */
+ e = multi->msglist->head;
+
+ msg = e->ptr;
+
+ /* remove the extracted entry */
+ Curl_llist_remove(multi->msglist, e, NULL);
+
+ *msgs_in_queue = curlx_uztosi(Curl_llist_count(multi->msglist));
+
+ return &msg->extmsg;
+ }
+ else
+ return NULL;
+}
+
+/*
+ * singlesocket() checks what sockets we deal with and their "action state"
+ * and if we have a different state in any of those sockets from last time we
+ * call the callback accordingly.
+ */
+static void singlesocket(struct Curl_multi *multi,
+ struct SessionHandle *data)
+{
+ curl_socket_t socks[MAX_SOCKSPEREASYHANDLE];
+ int i;
+ struct Curl_sh_entry *entry;
+ curl_socket_t s;
+ int num;
+ unsigned int curraction;
+ bool remove_sock_from_hash;
+
+ for(i=0; i< MAX_SOCKSPEREASYHANDLE; i++)
+ socks[i] = CURL_SOCKET_BAD;
+
+ /* Fill in the 'current' struct with the state as it is now: what sockets to
+ supervise and for what actions */
+ curraction = multi_getsock(data, socks, MAX_SOCKSPEREASYHANDLE);
+
+ /* We have 0 .. N sockets already and we get to know about the 0 .. M
+ sockets we should have from now on. Detect the differences, remove no
+ longer supervised ones and add new ones */
+
+ /* walk over the sockets we got right now */
+ for(i=0; (i< MAX_SOCKSPEREASYHANDLE) &&
+ (curraction & (GETSOCK_READSOCK(i) | GETSOCK_WRITESOCK(i)));
+ i++) {
+ int action = CURL_POLL_NONE;
+
+ s = socks[i];
+
+ /* get it from the hash */
+ entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+ if(curraction & GETSOCK_READSOCK(i))
+ action |= CURL_POLL_IN;
+ if(curraction & GETSOCK_WRITESOCK(i))
+ action |= CURL_POLL_OUT;
+
+ if(entry) {
+ /* yeps, already present so check if it has the same action set */
+ if(entry->action == action)
+ /* same, continue */
+ continue;
+ }
+ else {
+ /* this is a socket we didn't have before, add it! */
+ entry = sh_addentry(multi->sockhash, s, data);
+ if(!entry)
+ /* fatal */
+ return;
+ }
+
+ /* we know (entry != NULL) at this point, see the logic above */
+ if(multi->socket_cb)
+ multi->socket_cb(data,
+ s,
+ action,
+ multi->socket_userp,
+ entry->socketp);
+
+ entry->action = action; /* store the current action state */
+ }
+
+ num = i; /* number of sockets */
+
+ /* when we've walked over all the sockets we should have right now, we must
+ make sure to detect sockets that are removed */
+ for(i=0; i< data->numsocks; i++) {
+ int j;
+ s = data->sockets[i];
+ for(j=0; j<num; j++) {
+ if(s == socks[j]) {
+ /* this is still supervised */
+ s = CURL_SOCKET_BAD;
+ break;
+ }
+ }
+ if(s != CURL_SOCKET_BAD) {
+
+ /* this socket has been removed. Tell the app to remove it */
+ remove_sock_from_hash = TRUE;
+
+ entry = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+ if(entry) {
+ /* check if the socket to be removed serves a connection which has
+ other easy-s in a pipeline. In this case the socket should not be
+ removed. */
+ struct connectdata *easy_conn = data->easy_conn;
+ if(easy_conn) {
+ if(easy_conn->recv_pipe && easy_conn->recv_pipe->size > 1) {
+ /* the handle should not be removed from the pipe yet */
+ remove_sock_from_hash = FALSE;
+
+ /* Update the sockhash entry to instead point to the next in line
+ for the recv_pipe, or the first (in case this particular easy
+ isn't already) */
+ if(entry->easy == data) {
+ if(isHandleAtHead(data, easy_conn->recv_pipe))
+ entry->easy = easy_conn->recv_pipe->head->next->ptr;
+ else
+ entry->easy = easy_conn->recv_pipe->head->ptr;
+ }
+ }
+ if(easy_conn->send_pipe && easy_conn->send_pipe->size > 1) {
+ /* the handle should not be removed from the pipe yet */
+ remove_sock_from_hash = FALSE;
+
+ /* Update the sockhash entry to instead point to the next in line
+ for the send_pipe, or the first (in case this particular easy
+ isn't already) */
+ if(entry->easy == data) {
+ if(isHandleAtHead(data, easy_conn->send_pipe))
+ entry->easy = easy_conn->send_pipe->head->next->ptr;
+ else
+ entry->easy = easy_conn->send_pipe->head->ptr;
+ }
+ }
+ /* Don't worry about overwriting recv_pipe head with send_pipe_head,
+ when action will be asked on the socket (see multi_socket()), the
+ head of the correct pipe will be taken according to the
+ action. */
+ }
+ }
+ else
+ /* just a precaution, this socket really SHOULD be in the hash already
+ but in case it isn't, we don't have to tell the app to remove it
+ either since it never got to know about it */
+ remove_sock_from_hash = FALSE;
+
+ if(remove_sock_from_hash) {
+ /* in this case 'entry' is always non-NULL */
+ if(multi->socket_cb)
+ multi->socket_cb(data,
+ s,
+ CURL_POLL_REMOVE,
+ multi->socket_userp,
+ entry->socketp);
+ sh_delentry(multi->sockhash, s);
+ }
+
+ }
+ }
+
+ memcpy(data->sockets, socks, num*sizeof(curl_socket_t));
+ data->numsocks = num;
+}
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using have just been closed. This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct connectdata *conn, curl_socket_t s)
+{
+ struct Curl_multi *multi = conn->data->multi;
+ if(multi) {
+ /* this is set if this connection is part of a handle that is added to
+ a multi handle, and only then this is necessary */
+ struct Curl_sh_entry *entry =
+ Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+ if(entry) {
+ if(multi->socket_cb)
+ multi->socket_cb(conn->data, s, CURL_POLL_REMOVE,
+ multi->socket_userp,
+ entry->socketp);
+
+ /* now remove it from the socket hash */
+ sh_delentry(multi->sockhash, s);
+ }
+ }
+}
+
+
+
+/*
+ * add_next_timeout()
+ *
+ * Each SessionHandle has a list of timeouts. The add_next_timeout() is called
+ * when it has just been removed from the splay tree because the timeout has
+ * expired. This function is then to advance in the list to pick the next
+ * timeout to use (skip the already expired ones) and add this node back to
+ * the splay tree again.
+ *
+ * The splay tree only has each sessionhandle as a single node and the nearest
+ * timeout is used to sort it on.
+ */
+static CURLMcode add_next_timeout(struct timeval now,
+ struct Curl_multi *multi,
+ struct SessionHandle *d)
+{
+ struct timeval *tv = &d->state.expiretime;
+ struct curl_llist *list = d->state.timeoutlist;
+ struct curl_llist_element *e;
+
+ /* move over the timeout list for this specific handle and remove all
+ timeouts that are now passed tense and store the next pending
+ timeout in *tv */
+ for(e = list->head; e; ) {
+ struct curl_llist_element *n = e->next;
+ long diff = curlx_tvdiff(*(struct timeval *)e->ptr, now);
+ if(diff <= 0)
+ /* remove outdated entry */
+ Curl_llist_remove(list, e, NULL);
+ else
+ /* the list is sorted so get out on the first mismatch */
+ break;
+ e = n;
+ }
+ e = list->head;
+ if(!e) {
+ /* clear the expire times within the handles that we remove from the
+ splay tree */
+ tv->tv_sec = 0;
+ tv->tv_usec = 0;
+ }
+ else {
+ /* copy the first entry to 'tv' */
+ memcpy(tv, e->ptr, sizeof(*tv));
+
+ /* remove first entry from list */
+ Curl_llist_remove(list, e, NULL);
+
+ /* insert this node again into the splay */
+ multi->timetree = Curl_splayinsert(*tv, multi->timetree,
+ &d->state.timenode);
+ }
+ return CURLM_OK;
+}
+
+static CURLMcode multi_socket(struct Curl_multi *multi,
+ bool checkall,
+ curl_socket_t s,
+ int ev_bitmask,
+ int *running_handles)
+{
+ CURLMcode result = CURLM_OK;
+ struct SessionHandle *data = NULL;
+ struct Curl_tree *t;
+ struct timeval now = Curl_tvnow();
+
+ if(checkall) {
+ /* *perform() deals with running_handles on its own */
+ result = curl_multi_perform(multi, running_handles);
+
+ /* walk through each easy handle and do the socket state change magic
+ and callbacks */
+ data=multi->easyp;
+ while(data) {
+ singlesocket(multi, data);
+ data = data->next;
+ }
+
+ /* or should we fall-through and do the timer-based stuff? */
+ return result;
+ }
+ else if(s != CURL_SOCKET_TIMEOUT) {
+
+ struct Curl_sh_entry *entry =
+ Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+ if(!entry)
+ /* Unmatched socket, we can't act on it but we ignore this fact. In
+ real-world tests it has been proved that libevent can in fact give
+ the application actions even though the socket was just previously
+ asked to get removed, so thus we better survive stray socket actions
+ and just move on. */
+ ;
+ else {
+ data = entry->easy;
+
+ if(data->magic != CURLEASY_MAGIC_NUMBER)
+ /* bad bad bad bad bad bad bad */
+ return CURLM_INTERNAL_ERROR;
+
+ /* If the pipeline is enabled, take the handle which is in the head of
+ the pipeline. If we should write into the socket, take the send_pipe
+ head. If we should read from the socket, take the recv_pipe head. */
+ if(data->easy_conn) {
+ if((ev_bitmask & CURL_POLL_OUT) &&
+ data->easy_conn->send_pipe &&
+ data->easy_conn->send_pipe->head)
+ data = data->easy_conn->send_pipe->head->ptr;
+ else if((ev_bitmask & CURL_POLL_IN) &&
+ data->easy_conn->recv_pipe &&
+ data->easy_conn->recv_pipe->head)
+ data = data->easy_conn->recv_pipe->head->ptr;
+ }
+
+ if(data->easy_conn &&
+ !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
+ /* set socket event bitmask if they're not locked */
+ data->easy_conn->cselect_bits = ev_bitmask;
+
+ do
+ result = multi_runsingle(multi, now, data);
+ while(CURLM_CALL_MULTI_PERFORM == result);
+
+ if(data->easy_conn &&
+ !(data->easy_conn->handler->flags & PROTOPT_DIRLOCK))
+ /* clear the bitmask only if not locked */
+ data->easy_conn->cselect_bits = 0;
+
+ if(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data);
+
+ /* Now we fall-through and do the timer-based stuff, since we don't want
+ to force the user to have to deal with timeouts as long as at least
+ one connection in fact has traffic. */
+
+ data = NULL; /* set data to NULL again to avoid calling
+ multi_runsingle() in case there's no need to */
+ }
+ }
+
+ /* Compensate for bad precision timers that might've triggered too early.
+
+ This precaution was added in commit 2c72732ebf3da5e as a result of bad
+ resolution in the windows function use(d).
+
+ The problematic case here is when using the multi_socket API and libcurl
+ has told the application about a timeout, and that timeout is what fires
+ off a bit early. As we don't have any IDs associated with the timeout we
+ can't tell which timeout that fired off but we only have the times to use
+ to check what to do. If it fires off too early, we don't run the correct
+ actions and we don't tell the application again about the same timeout as
+ was already first in the queue...
+
+ Originally we made the timeouts run 40 milliseconds early on all systems,
+ but now we have an #ifdef setup to provide a decent precaution inaccuracy
+ margin.
+ */
+
+ now.tv_usec += MULTI_TIMEOUT_INACCURACY;
+ if(now.tv_usec >= 1000000) {
+ now.tv_sec++;
+ now.tv_usec -= 1000000;
+ }
+
+ /*
+ * The loop following here will go on as long as there are expire-times left
+ * to process in the splay and 'data' will be re-assigned for every expired
+ * handle we deal with.
+ */
+ do {
+ /* the first loop lap 'data' can be NULL */
+ if(data) {
+ do
+ result = multi_runsingle(multi, now, data);
+ while(CURLM_CALL_MULTI_PERFORM == result);
+
+ if(CURLM_OK >= result)
+ /* get the socket(s) and check if the state has been changed since
+ last */
+ singlesocket(multi, data);
+ }
+
+ /* Check if there's one (more) expired timer to deal with! This function
+ extracts a matching node if there is one */
+
+ multi->timetree = Curl_splaygetbest(now, multi->timetree, &t);
+ if(t) {
+ data = t->payload; /* assign this for next loop */
+ (void)add_next_timeout(now, multi, t->payload);
+ }
+
+ } while(t);
+
+ *running_handles = multi->num_alive;
+ return result;
+}
+
+#undef curl_multi_setopt
+CURLMcode curl_multi_setopt(CURLM *multi_handle,
+ CURLMoption option, ...)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ CURLMcode res = CURLM_OK;
+ va_list param;
+
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ va_start(param, option);
+
+ switch(option) {
+ case CURLMOPT_SOCKETFUNCTION:
+ multi->socket_cb = va_arg(param, curl_socket_callback);
+ break;
+ case CURLMOPT_SOCKETDATA:
+ multi->socket_userp = va_arg(param, void *);
+ break;
+ case CURLMOPT_PIPELINING:
+ multi->pipelining_enabled = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+ case CURLMOPT_TIMERFUNCTION:
+ multi->timer_cb = va_arg(param, curl_multi_timer_callback);
+ break;
+ case CURLMOPT_TIMERDATA:
+ multi->timer_userp = va_arg(param, void *);
+ break;
+ case CURLMOPT_MAXCONNECTS:
+ multi->maxconnects = va_arg(param, long);
+ break;
+ case CURLMOPT_MAX_HOST_CONNECTIONS:
+ multi->max_host_connections = va_arg(param, long);
+ break;
+ case CURLMOPT_MAX_PIPELINE_LENGTH:
+ multi->max_pipeline_length = va_arg(param, long);
+ break;
+ case CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE:
+ multi->content_length_penalty_size = va_arg(param, long);
+ break;
+ case CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE:
+ multi->chunk_length_penalty_size = va_arg(param, long);
+ break;
+ case CURLMOPT_PIPELINING_SITE_BL:
+ res = Curl_pipeline_set_site_blacklist(va_arg(param, char **),
+ &multi->pipelining_site_bl);
+ break;
+ case CURLMOPT_PIPELINING_SERVER_BL:
+ res = Curl_pipeline_set_server_blacklist(va_arg(param, char **),
+ &multi->pipelining_server_bl);
+ break;
+ case CURLMOPT_MAX_TOTAL_CONNECTIONS:
+ multi->max_total_connections = va_arg(param, long);
+ break;
+ default:
+ res = CURLM_UNKNOWN_OPTION;
+ break;
+ }
+ va_end(param);
+ return res;
+}
+
+/* we define curl_multi_socket() in the public multi.h header */
+#undef curl_multi_socket
+
+CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s,
+ int *running_handles)
+{
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+ 0, running_handles);
+ if(CURLM_OK >= result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
+}
+
+CURLMcode curl_multi_socket_action(CURLM *multi_handle, curl_socket_t s,
+ int ev_bitmask, int *running_handles)
+{
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle, FALSE, s,
+ ev_bitmask, running_handles);
+ if(CURLM_OK >= result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
+}
+
+CURLMcode curl_multi_socket_all(CURLM *multi_handle, int *running_handles)
+
+{
+ CURLMcode result = multi_socket((struct Curl_multi *)multi_handle,
+ TRUE, CURL_SOCKET_BAD, 0, running_handles);
+ if(CURLM_OK >= result)
+ update_timer((struct Curl_multi *)multi_handle);
+ return result;
+}
+
+static CURLMcode multi_timeout(struct Curl_multi *multi,
+ long *timeout_ms)
+{
+ static struct timeval tv_zero = {0,0};
+
+ if(multi->timetree) {
+ /* we have a tree of expire times */
+ struct timeval now = Curl_tvnow();
+
+ /* splay the lowest to the bottom */
+ multi->timetree = Curl_splay(tv_zero, multi->timetree);
+
+ if(Curl_splaycomparekeys(multi->timetree->key, now) > 0) {
+ /* some time left before expiration */
+ *timeout_ms = curlx_tvdiff(multi->timetree->key, now);
+ if(!*timeout_ms)
+ /*
+ * Since we only provide millisecond resolution on the returned value
+ * and the diff might be less than one millisecond here, we don't
+ * return zero as that may cause short bursts of busyloops on fast
+ * processors while the diff is still present but less than one
+ * millisecond! instead we return 1 until the time is ripe.
+ */
+ *timeout_ms=1;
+ }
+ else
+ /* 0 means immediately */
+ *timeout_ms = 0;
+ }
+ else
+ *timeout_ms = -1;
+
+ return CURLM_OK;
+}
+
+CURLMcode curl_multi_timeout(CURLM *multi_handle,
+ long *timeout_ms)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+
+ /* First, make some basic checks that the CURLM handle is a good handle */
+ if(!GOOD_MULTI_HANDLE(multi))
+ return CURLM_BAD_HANDLE;
+
+ return multi_timeout(multi, timeout_ms);
+}
+
+/*
+ * Tell the application it should update its timers, if it subscribes to the
+ * update timer callback.
+ */
+static int update_timer(struct Curl_multi *multi)
+{
+ long timeout_ms;
+
+ if(!multi->timer_cb)
+ return 0;
+ if(multi_timeout(multi, &timeout_ms)) {
+ return -1;
+ }
+ if(timeout_ms < 0) {
+ static const struct timeval none={0,0};
+ if(Curl_splaycomparekeys(none, multi->timer_lastcall)) {
+ multi->timer_lastcall = none;
+ /* there's no timeout now but there was one previously, tell the app to
+ disable it */
+ return multi->timer_cb((CURLM*)multi, -1, multi->timer_userp);
+ }
+ return 0;
+ }
+
+ /* When multi_timeout() is done, multi->timetree points to the node with the
+ * timeout we got the (relative) time-out time for. We can thus easily check
+ * if this is the same (fixed) time as we got in a previous call and then
+ * avoid calling the callback again. */
+ if(Curl_splaycomparekeys(multi->timetree->key, multi->timer_lastcall) == 0)
+ return 0;
+
+ multi->timer_lastcall = multi->timetree->key;
+
+ return multi->timer_cb((CURLM*)multi, timeout_ms, multi->timer_userp);
+}
+
+void Curl_multi_set_easy_connection(struct SessionHandle *handle,
+ struct connectdata *conn)
+{
+ handle->easy_conn = conn;
+}
+
+static bool isHandleAtHead(struct SessionHandle *handle,
+ struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr = pipeline->head;
+ if(curr)
+ return (curr->ptr == handle) ? TRUE : FALSE;
+
+ return FALSE;
+}
+
+/*
+ * multi_freetimeout()
+ *
+ * Callback used by the llist system when a single timeout list entry is
+ * destroyed.
+ */
+static void multi_freetimeout(void *user, void *entryptr)
+{
+ (void)user;
+
+ /* the entry was plain malloc()'ed */
+ free(entryptr);
+}
+
+/*
+ * multi_addtimeout()
+ *
+ * Add a timestamp to the list of timeouts. Keep the list sorted so that head
+ * of list is always the timeout nearest in time.
+ *
+ */
+static CURLMcode
+multi_addtimeout(struct curl_llist *timeoutlist,
+ struct timeval *stamp)
+{
+ struct curl_llist_element *e;
+ struct timeval *timedup;
+ struct curl_llist_element *prev = NULL;
+
+ timedup = malloc(sizeof(*timedup));
+ if(!timedup)
+ return CURLM_OUT_OF_MEMORY;
+
+ /* copy the timestamp */
+ memcpy(timedup, stamp, sizeof(*timedup));
+
+ if(Curl_llist_count(timeoutlist)) {
+ /* find the correct spot in the list */
+ for(e = timeoutlist->head; e; e = e->next) {
+ struct timeval *checktime = e->ptr;
+ long diff = curlx_tvdiff(*checktime, *timedup);
+ if(diff > 0)
+ break;
+ prev = e;
+ }
+
+ }
+ /* else
+ this is the first timeout on the list */
+
+ if(!Curl_llist_insert_next(timeoutlist, prev, timedup)) {
+ free(timedup);
+ return CURLM_OUT_OF_MEMORY;
+ }
+
+ return CURLM_OK;
+}
+
+/*
+ * Curl_expire()
+ *
+ * given a number of milliseconds from now to use to set the 'act before
+ * this'-time for the transfer, to be extracted by curl_multi_timeout()
+ *
+ * Note that the timeout will be added to a queue of timeouts if it defines a
+ * moment in time that is later than the current head of queue.
+ *
+ * Pass zero to clear all timeout values for this handle.
+*/
+void Curl_expire(struct SessionHandle *data, long milli)
+{
+ struct Curl_multi *multi = data->multi;
+ struct timeval *nowp = &data->state.expiretime;
+ int rc;
+
+ /* this is only interesting while there is still an associated multi struct
+ remaining! */
+ if(!multi)
+ return;
+
+ if(!milli) {
+ /* No timeout, clear the time data. */
+ if(nowp->tv_sec || nowp->tv_usec) {
+ /* Since this is an cleared time, we must remove the previous entry from
+ the splay tree */
+ struct curl_llist *list = data->state.timeoutlist;
+
+ rc = Curl_splayremovebyaddr(multi->timetree,
+ &data->state.timenode,
+ &multi->timetree);
+ if(rc)
+ infof(data, "Internal error clearing splay node = %d\n", rc);
+
+ /* flush the timeout list too */
+ while(list->size > 0)
+ Curl_llist_remove(list, list->tail, NULL);
+
+#ifdef DEBUGBUILD
+ infof(data, "Expire cleared\n");
+#endif
+ nowp->tv_sec = 0;
+ nowp->tv_usec = 0;
+ }
+ }
+ else {
+ struct timeval set;
+
+ set = Curl_tvnow();
+ set.tv_sec += milli/1000;
+ set.tv_usec += (milli%1000)*1000;
+
+ if(set.tv_usec >= 1000000) {
+ set.tv_sec++;
+ set.tv_usec -= 1000000;
+ }
+
+ if(nowp->tv_sec || nowp->tv_usec) {
+ /* This means that the struct is added as a node in the splay tree.
+ Compare if the new time is earlier, and only remove-old/add-new if it
+ is. */
+ long diff = curlx_tvdiff(set, *nowp);
+ if(diff > 0) {
+ /* the new expire time was later so just add it to the queue
+ and get out */
+ multi_addtimeout(data->state.timeoutlist, &set);
+ return;
+ }
+
+ /* the new time is newer than the presently set one, so add the current
+ to the queue and update the head */
+ multi_addtimeout(data->state.timeoutlist, nowp);
+
+ /* Since this is an updated time, we must remove the previous entry from
+ the splay tree first and then re-add the new value */
+ rc = Curl_splayremovebyaddr(multi->timetree,
+ &data->state.timenode,
+ &multi->timetree);
+ if(rc)
+ infof(data, "Internal error removing splay node = %d\n", rc);
+ }
+
+ *nowp = set;
+ data->state.timenode.payload = data;
+ multi->timetree = Curl_splayinsert(*nowp,
+ multi->timetree,
+ &data->state.timenode);
+ }
+#if 0
+ Curl_splayprint(multi->timetree, 0, TRUE);
+#endif
+}
+
+CURLMcode curl_multi_assign(CURLM *multi_handle,
+ curl_socket_t s, void *hashp)
+{
+ struct Curl_sh_entry *there = NULL;
+ struct Curl_multi *multi = (struct Curl_multi *)multi_handle;
+
+ if(s != CURL_SOCKET_BAD)
+ there = Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(curl_socket_t));
+
+ if(!there)
+ return CURLM_BAD_SOCKET;
+
+ there->socketp = hashp;
+
+ return CURLM_OK;
+}
+
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi)
+{
+ return multi ? multi->max_host_connections : 0;
+}
+
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi)
+{
+ return multi ? multi->max_total_connections : 0;
+}
+
+size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi)
+{
+ return multi ? multi->max_pipeline_length : 0;
+}
+
+curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi)
+{
+ return multi ? multi->content_length_penalty_size : 0;
+}
+
+curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi)
+{
+ return multi ? multi->chunk_length_penalty_size : 0;
+}
+
+struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi)
+{
+ return multi->pipelining_site_bl;
+}
+
+struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi)
+{
+ return multi->pipelining_server_bl;
+}
+
+void Curl_multi_process_pending_handles(struct Curl_multi *multi)
+{
+ struct SessionHandle *data;
+
+ data=multi->easyp;
+ while(data) {
+ if(data->mstate == CURLM_STATE_CONNECT_PEND) {
+ multistate(data, CURLM_STATE_CONNECT);
+ /* Make sure that the handle will be processed soonish. */
+ Curl_expire(data, 1);
+ }
+ data = data->next; /* operate on next handle */
+ }
+}
+
+#ifdef DEBUGBUILD
+void Curl_multi_dump(const struct Curl_multi *multi_handle)
+{
+ struct Curl_multi *multi=(struct Curl_multi *)multi_handle;
+ struct SessionHandle *data;
+ int i;
+ fprintf(stderr, "* Multi status: %d handles, %d alive\n",
+ multi->num_easy, multi->num_alive);
+ for(data=multi->easyp; data; data = data->next) {
+ if(data->mstate < CURLM_STATE_COMPLETED) {
+ /* only display handles that are not completed */
+ fprintf(stderr, "handle %p, state %s, %d sockets\n",
+ (void *)data,
+ statename[data->mstate], data->numsocks);
+ for(i=0; i < data->numsocks; i++) {
+ curl_socket_t s = data->sockets[i];
+ struct Curl_sh_entry *entry =
+ Curl_hash_pick(multi->sockhash, (char *)&s, sizeof(s));
+
+ fprintf(stderr, "%d ", (int)s);
+ if(!entry) {
+ fprintf(stderr, "INTERNAL CONFUSION\n");
+ continue;
+ }
+ fprintf(stderr, "[%s %s] ",
+ entry->action&CURL_POLL_IN?"RECVING":"",
+ entry->action&CURL_POLL_OUT?"SENDING":"");
+ }
+ if(data->numsocks)
+ fprintf(stderr, "\n");
+ }
+ }
+}
+#endif
diff --git a/libs/libcurl/src/multihandle.h b/libs/libcurl/src/multihandle.h
new file mode 100644
index 0000000000..552aa93797
--- /dev/null
+++ b/libs/libcurl/src/multihandle.h
@@ -0,0 +1,139 @@
+#ifndef HEADER_CURL_MULTIHANDLE_H
+#define HEADER_CURL_MULTIHANDLE_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.
+ *
+ ***************************************************************************/
+
+struct Curl_message {
+ /* the 'CURLMsg' is the part that is visible to the external user */
+ struct CURLMsg extmsg;
+};
+
+/* NOTE: if you add a state here, add the name to the statename[] array as
+ well!
+*/
+typedef enum {
+ CURLM_STATE_INIT, /* 0 - start in this state */
+ CURLM_STATE_CONNECT_PEND, /* 1 - no connections, waiting for one */
+ CURLM_STATE_CONNECT, /* 2 - resolve/connect has been sent off */
+ CURLM_STATE_WAITRESOLVE, /* 3 - awaiting the resolve to finalize */
+ CURLM_STATE_WAITCONNECT, /* 4 - awaiting the connect to finalize */
+ CURLM_STATE_WAITPROXYCONNECT, /* 5 - awaiting proxy CONNECT to finalize */
+ CURLM_STATE_PROTOCONNECT, /* 6 - completing the protocol-specific connect
+ phase */
+ CURLM_STATE_WAITDO, /* 7 - wait for our turn to send the request */
+ CURLM_STATE_DO, /* 8 - start send off the request (part 1) */
+ CURLM_STATE_DOING, /* 9 - sending off the request (part 1) */
+ CURLM_STATE_DO_MORE, /* 10 - send off the request (part 2) */
+ CURLM_STATE_DO_DONE, /* 11 - done sending off request */
+ CURLM_STATE_WAITPERFORM, /* 12 - wait for our turn to read the response */
+ CURLM_STATE_PERFORM, /* 13 - transfer data */
+ CURLM_STATE_TOOFAST, /* 14 - wait because limit-rate exceeded */
+ CURLM_STATE_DONE, /* 15 - post data transfer operation */
+ CURLM_STATE_COMPLETED, /* 16 - operation complete */
+ CURLM_STATE_MSGSENT, /* 17 - the operation complete message is sent */
+ CURLM_STATE_LAST /* 18 - not a true state, never use this */
+} CURLMstate;
+
+/* we support N sockets per easy handle. Set the corresponding bit to what
+ action we should wait for */
+#define MAX_SOCKSPEREASYHANDLE 5
+#define GETSOCK_READABLE (0x00ff)
+#define GETSOCK_WRITABLE (0xff00)
+
+/* This is the struct known as CURLM on the outside */
+struct Curl_multi {
+ /* First a simple identifier to easier detect if a user mix up
+ this multi handle with an easy handle. Set this to CURL_MULTI_HANDLE. */
+ long type;
+
+ /* We have a doubly-linked circular list with easy handles */
+ struct SessionHandle *easyp;
+ struct SessionHandle *easylp; /* last node */
+
+ int num_easy; /* amount of entries in the linked list above. */
+ int num_alive; /* amount of easy handles that are added but have not yet
+ reached COMPLETE state */
+
+ struct curl_llist *msglist; /* a list of messages from completed transfers */
+
+ /* callback function and user data pointer for the *socket() API */
+ curl_socket_callback socket_cb;
+ void *socket_userp;
+
+ /* Hostname cache */
+ struct curl_hash *hostcache;
+
+ /* timetree points to the splay-tree of time nodes to figure out expire
+ times of all currently set timers */
+ struct Curl_tree *timetree;
+
+ /* 'sockhash' is the lookup hash for socket descriptor => easy handles (note
+ the pluralis form, there can be more than one easy handle waiting on the
+ same actual socket) */
+ struct curl_hash *sockhash;
+
+ /* Whether pipelining is enabled for this multi handle */
+ bool pipelining_enabled;
+
+ /* Shared connection cache (bundles)*/
+ struct conncache *conn_cache;
+
+ /* This handle will be used for closing the cached connections in
+ curl_multi_cleanup() */
+ struct SessionHandle *closure_handle;
+
+ long maxconnects; /* if >0, a fixed limit of the maximum number of entries
+ we're allowed to grow the connection cache to */
+
+ long max_host_connections; /* if >0, a fixed limit of the maximum number
+ of connections per host */
+
+ long max_total_connections; /* if >0, a fixed limit of the maximum number
+ of connections in total */
+
+ long max_pipeline_length; /* if >0, maximum number of requests in a
+ pipeline */
+
+ long content_length_penalty_size; /* a connection with a
+ content-length bigger than
+ this is not considered
+ for pipelining */
+
+ long chunk_length_penalty_size; /* a connection with a chunk length
+ bigger than this is not
+ considered for pipelining */
+
+ struct curl_llist *pipelining_site_bl; /* List of sites that are blacklisted
+ from pipelining */
+
+ struct curl_llist *pipelining_server_bl; /* List of server types that are
+ blacklisted from pipelining */
+
+ /* timer callback and user data pointer for the *socket() API */
+ curl_multi_timer_callback timer_cb;
+ void *timer_userp;
+ struct timeval timer_lastcall; /* the fixed time for the timeout for the
+ previous callback */
+};
+
+#endif /* HEADER_CURL_MULTIHANDLE_H */
+
diff --git a/libs/libcurl/src/multiif.h b/libs/libcurl/src/multiif.h
new file mode 100644
index 0000000000..e61c5c6f2c
--- /dev/null
+++ b/libs/libcurl/src/multiif.h
@@ -0,0 +1,104 @@
+#ifndef HEADER_CURL_MULTIIF_H
+#define HEADER_CURL_MULTIIF_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.
+ *
+ ***************************************************************************/
+
+/* See multi_socket() for the explanation of this constant. Counted in number
+ of microseconds. */
+#ifdef WIN32
+#define MULTI_TIMEOUT_INACCURACY 40000
+#else
+#define MULTI_TIMEOUT_INACCURACY 3000
+#endif
+
+/*
+ * Prototypes for library-wide functions provided by multi.c
+ */
+void Curl_expire(struct SessionHandle *data, long milli);
+
+bool Curl_multi_pipeline_enabled(const struct Curl_multi* multi);
+void Curl_multi_handlePipeBreak(struct SessionHandle *data);
+
+/* Internal version of curl_multi_init() accepts size parameters for the
+ socket and connection hashes */
+struct Curl_multi *Curl_multi_handle(int hashsize, int chashsize);
+
+/* the write bits start at bit 16 for the *getsock() bitmap */
+#define GETSOCK_WRITEBITSTART 16
+
+#define GETSOCK_BLANK 0 /* no bits set */
+
+/* set the bit for the given sock number to make the bitmap for writable */
+#define GETSOCK_WRITESOCK(x) (1 << (GETSOCK_WRITEBITSTART + (x)))
+
+/* set the bit for the given sock number to make the bitmap for readable */
+#define GETSOCK_READSOCK(x) (1 << (x))
+
+#ifdef DEBUGBUILD
+ /*
+ * Curl_multi_dump is not a stable public function, this is only meant to
+ * allow easier tracking of the internal handle's state and what sockets
+ * they use. Only for research and development DEBUGBUILD enabled builds.
+ */
+void Curl_multi_dump(const struct Curl_multi *multi_handle);
+#endif
+
+/* Update the current connection of a One_Easy handle */
+void Curl_multi_set_easy_connection(struct SessionHandle *handle,
+ struct connectdata *conn);
+
+void Curl_multi_process_pending_handles(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_HOST_CONNECTIONS option */
+size_t Curl_multi_max_host_connections(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_PIPELINE_LENGTH option */
+size_t Curl_multi_max_pipeline_length(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE option */
+curl_off_t Curl_multi_content_length_penalty_size(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE option */
+curl_off_t Curl_multi_chunk_length_penalty_size(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_PIPELINING_SITE_BL option */
+struct curl_llist *Curl_multi_pipelining_site_bl(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_PIPELINING_SERVER_BL option */
+struct curl_llist *Curl_multi_pipelining_server_bl(struct Curl_multi *multi);
+
+/* Return the value of the CURLMOPT_MAX_TOTAL_CONNECTIONS option */
+size_t Curl_multi_max_total_connections(struct Curl_multi *multi);
+
+/*
+ * Curl_multi_closed()
+ *
+ * Used by the connect code to tell the multi_socket code that one of the
+ * sockets we were using have just been closed. This function will then
+ * remove it from the sockethash for this handle to make the multi_socket API
+ * behave properly, especially for the case when libcurl will create another
+ * socket again and it gets the same file descriptor number.
+ */
+
+void Curl_multi_closed(struct connectdata *conn, curl_socket_t s);
+
+#endif /* HEADER_CURL_MULTIIF_H */
diff --git a/libs/libcurl/src/netrc.c b/libs/libcurl/src/netrc.c
new file mode 100644
index 0000000000..6ff92bb33f
--- /dev/null
+++ b/libs/libcurl/src/netrc.c
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_PWD_H
+#include <pwd.h>
+#endif
+
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "strequal.h"
+#include "strtok.h"
+#include "curl_memory.h"
+#include "rawstr.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* Get user and password from .netrc when given a machine name */
+
+enum host_lookup_state {
+ NOTHING,
+ HOSTFOUND, /* the 'machine' keyword was found */
+ HOSTVALID /* this is "our" machine! */
+};
+
+/*
+ * @unittest: 1304
+ *
+ * *loginp and *passwordp MUST be allocated if they aren't NULL when passed
+ * in.
+ */
+int Curl_parsenetrc(const char *host,
+ char **loginp,
+ char **passwordp,
+ char *netrcfile)
+{
+ FILE *file;
+ int retcode=1;
+ int specific_login = (**loginp != 0);
+ char *home = NULL;
+ bool home_alloc = FALSE;
+ bool netrc_alloc = FALSE;
+ enum host_lookup_state state=NOTHING;
+
+ char state_login=0; /* Found a login keyword */
+ char state_password=0; /* Found a password keyword */
+ int state_our_login=FALSE; /* With specific_login, found *our* login name */
+
+#define NETRC DOT_CHAR "netrc"
+
+ if(!netrcfile) {
+ home = curl_getenv("HOME"); /* portable environment reader */
+ if(home) {
+ home_alloc = TRUE;
+#if defined(HAVE_GETPWUID) && defined(HAVE_GETEUID)
+ }
+ else {
+ struct passwd *pw;
+ pw= getpwuid(geteuid());
+ if(pw) {
+ home = pw->pw_dir;
+ }
+#endif
+ }
+
+ if(!home)
+ return -1;
+
+ netrcfile = curl_maprintf("%s%s%s", home, DIR_CHAR, NETRC);
+ if(!netrcfile) {
+ if(home_alloc)
+ free(home);
+ return -1;
+ }
+ netrc_alloc = TRUE;
+ }
+
+ file = fopen(netrcfile, "r");
+ if(file) {
+ char *tok;
+ char *tok_buf;
+ bool done=FALSE;
+ char netrcbuffer[256];
+ int netrcbuffsize = sizeof(netrcbuffer);
+
+ while(!done && fgets(netrcbuffer, netrcbuffsize, file)) {
+ tok=strtok_r(netrcbuffer, " \t\n", &tok_buf);
+ while(!done && tok) {
+
+ if(**loginp && **passwordp) {
+ done=TRUE;
+ break;
+ }
+
+ switch(state) {
+ case NOTHING:
+ if(Curl_raw_equal("machine", tok)) {
+ /* the next tok is the machine name, this is in itself the
+ delimiter that starts the stuff entered for this machine,
+ after this we need to search for 'login' and
+ 'password'. */
+ state=HOSTFOUND;
+ }
+ break;
+ case HOSTFOUND:
+ if(Curl_raw_equal(host, tok)) {
+ /* and yes, this is our host! */
+ state=HOSTVALID;
+ retcode=0; /* we did find our host */
+ }
+ else
+ /* not our host */
+ state=NOTHING;
+ break;
+ case HOSTVALID:
+ /* we are now parsing sub-keywords concerning "our" host */
+ if(state_login) {
+ if(specific_login) {
+ state_our_login = Curl_raw_equal(*loginp, tok);
+ }
+ else {
+ free(*loginp);
+ *loginp = strdup(tok);
+ if(!*loginp)
+ return -1; /* allocation failed */
+ }
+ state_login=0;
+ }
+ else if(state_password) {
+ if(state_our_login || !specific_login) {
+ free(*passwordp);
+ *passwordp = strdup(tok);
+ if(!*passwordp)
+ return -1; /* allocation failed */
+ }
+ state_password=0;
+ }
+ else if(Curl_raw_equal("login", tok))
+ state_login=1;
+ else if(Curl_raw_equal("password", tok))
+ state_password=1;
+ else if(Curl_raw_equal("machine", tok)) {
+ /* ok, there's machine here go => */
+ state = HOSTFOUND;
+ state_our_login = FALSE;
+ }
+ break;
+ } /* switch (state) */
+
+ tok = strtok_r(NULL, " \t\n", &tok_buf);
+ } /* while(tok) */
+ } /* while fgets() */
+
+ fclose(file);
+ }
+
+ if(home_alloc)
+ free(home);
+ if(netrc_alloc)
+ free(netrcfile);
+
+ return retcode;
+}
diff --git a/libs/libcurl/src/netrc.h b/libs/libcurl/src/netrc.h
new file mode 100644
index 0000000000..a145601148
--- /dev/null
+++ b/libs/libcurl/src/netrc.h
@@ -0,0 +1,36 @@
+#ifndef HEADER_CURL_NETRC_H
+#define HEADER_CURL_NETRC_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+/* returns -1 on failure, 0 if the host is found, 1 is the host isn't found */
+int Curl_parsenetrc(const char *host,
+ char **loginp,
+ char **passwordp,
+ char *filename);
+ /* Assume: (*passwordp)[0]=0, host[0] != 0.
+ * If (*loginp)[0] = 0, search for login and password within a machine
+ * section in the netrc.
+ * If (*loginp)[0] != 0, search for password within machine and login.
+ */
+
+#endif /* HEADER_CURL_NETRC_H */
diff --git a/libs/libcurl/src/non-ascii.c b/libs/libcurl/src/non-ascii.c
new file mode 100644
index 0000000000..91d6a54fcb
--- /dev/null
+++ b/libs/libcurl/src/non-ascii.c
@@ -0,0 +1,343 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 CURL_DOES_CONVERSIONS
+
+#include <curl/curl.h>
+
+#include "non-ascii.h"
+#include "formdata.h"
+#include "sendf.h"
+#include "urldata.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef HAVE_ICONV
+#include <iconv.h>
+/* set default codesets for iconv */
+#ifndef CURL_ICONV_CODESET_OF_NETWORK
+#define CURL_ICONV_CODESET_OF_NETWORK "ISO8859-1"
+#endif
+#ifndef CURL_ICONV_CODESET_FOR_UTF8
+#define CURL_ICONV_CODESET_FOR_UTF8 "UTF-8"
+#endif
+#define ICONV_ERROR (size_t)-1
+#endif /* HAVE_ICONV */
+
+/*
+ * Curl_convert_clone() returns a malloced copy of the source string (if
+ * returning CURLE_OK), with the data converted to network format.
+ */
+CURLcode Curl_convert_clone(struct SessionHandle *data,
+ const char *indata,
+ size_t insize,
+ char **outbuf)
+{
+ char *convbuf;
+ CURLcode result;
+
+ convbuf = malloc(insize);
+ if(!convbuf)
+ return CURLE_OUT_OF_MEMORY;
+
+ memcpy(convbuf, indata, insize);
+ result = Curl_convert_to_network(data, convbuf, insize);
+ if(result) {
+ free(convbuf);
+ return result;
+ }
+
+ *outbuf = convbuf; /* return the converted buffer */
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_to_network() is an internal function for performing ASCII
+ * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ */
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convtonetwork) {
+ /* use translation callback */
+ rc = data->set.convtonetwork(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_TO_NETWORK_FUNCTION callback returned %d: %s",
+ (int)rc, curl_easy_strerror(rc));
+ }
+ return rc;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->outbound_cd == (iconv_t)-1) {
+ data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ if(data->outbound_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->outbound_cd, (const char**)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "The Curl_convert_to_network iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_TO_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_network() is an internal function for performing ASCII
+ * conversions on non-ASCII platforms. It convers the buffer _in place_.
+ */
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convfromnetwork) {
+ /* use translation callback */
+ rc = data->set.convfromnetwork(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback returned %d: %s",
+ (int)rc, curl_easy_strerror(rc));
+ }
+ return rc;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ char *input_ptr, *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->inbound_cd == (iconv_t)-1) {
+ data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ if(data->inbound_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->inbound_cd, (const char **)&input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "Curl_convert_from_network iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_NETWORK_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_convert_from_utf8() is an internal function for performing UTF-8
+ * conversions on non-ASCII platforms.
+ */
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+ char *buffer, size_t length)
+{
+ CURLcode rc;
+
+ if(data->set.convfromutf8) {
+ /* use translation callback */
+ rc = data->set.convfromutf8(buffer, length);
+ if(rc != CURLE_OK) {
+ failf(data,
+ "CURLOPT_CONV_FROM_UTF8_FUNCTION callback returned %d: %s",
+ (int)rc, curl_easy_strerror(rc));
+ }
+ return rc;
+ }
+ else {
+#ifdef HAVE_ICONV
+ /* do the translation ourselves */
+ const char *input_ptr;
+ char *output_ptr;
+ size_t in_bytes, out_bytes, rc;
+ int error;
+
+ /* open an iconv conversion descriptor if necessary */
+ if(data->utf8_cd == (iconv_t)-1) {
+ data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+ if(data->utf8_cd == (iconv_t)-1) {
+ error = ERRNO;
+ failf(data,
+ "The iconv_open(\"%s\", \"%s\") call failed with errno %i: %s",
+ CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8,
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ }
+ /* call iconv */
+ input_ptr = output_ptr = buffer;
+ in_bytes = out_bytes = length;
+ rc = iconv(data->utf8_cd, &input_ptr, &in_bytes,
+ &output_ptr, &out_bytes);
+ if((rc == ICONV_ERROR) || (in_bytes != 0)) {
+ error = ERRNO;
+ failf(data,
+ "The Curl_convert_from_utf8 iconv call failed with errno %i: %s",
+ error, strerror(error));
+ return CURLE_CONV_FAILED;
+ }
+ if(output_ptr < input_ptr) {
+ /* null terminate the now shorter output string */
+ *output_ptr = 0x00;
+ }
+#else
+ failf(data, "CURLOPT_CONV_FROM_UTF8_FUNCTION callback required");
+ return CURLE_CONV_REQD;
+#endif /* HAVE_ICONV */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Init conversion stuff for a SessionHandle
+ */
+void Curl_convert_init(struct SessionHandle *data)
+{
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+ /* conversion descriptors for iconv calls */
+ data->outbound_cd = (iconv_t)-1;
+ data->inbound_cd = (iconv_t)-1;
+ data->utf8_cd = (iconv_t)-1;
+#else
+ (void)data;
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+}
+
+/*
+ * Setup conversion stuff for a SessionHandle
+ */
+void Curl_convert_setup(struct SessionHandle *data)
+{
+ data->inbound_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_OF_NETWORK);
+ data->outbound_cd = iconv_open(CURL_ICONV_CODESET_OF_NETWORK,
+ CURL_ICONV_CODESET_OF_HOST);
+ data->utf8_cd = iconv_open(CURL_ICONV_CODESET_OF_HOST,
+ CURL_ICONV_CODESET_FOR_UTF8);
+}
+
+/*
+ * Close conversion stuff for a SessionHandle
+ */
+
+void Curl_convert_close(struct SessionHandle *data)
+{
+#ifdef HAVE_ICONV
+ /* close iconv conversion descriptors */
+ if(data->inbound_cd != (iconv_t)-1) {
+ iconv_close(data->inbound_cd);
+ }
+ if(data->outbound_cd != (iconv_t)-1) {
+ iconv_close(data->outbound_cd);
+ }
+ if(data->utf8_cd != (iconv_t)-1) {
+ iconv_close(data->utf8_cd);
+ }
+#else
+ (void)data;
+#endif /* HAVE_ICONV */
+}
+
+/*
+ * Curl_convert_form() is used from http.c, this converts any form items that
+ need to be sent in the network encoding. Returns CURLE_OK on success.
+ */
+CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form)
+{
+ struct FormData *next;
+ CURLcode rc;
+
+ if(!form)
+ return CURLE_OK;
+
+ if(!data)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+
+ do {
+ next=form->next; /* the following form line */
+ if(form->type == FORM_DATA) {
+ rc = Curl_convert_to_network(data, form->line, form->length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(rc != CURLE_OK)
+ return rc;
+ }
+ } while((form = next) != NULL); /* continue */
+ return CURLE_OK;
+}
+
+#endif /* CURL_DOES_CONVERSIONS */
diff --git a/libs/libcurl/src/non-ascii.h b/libs/libcurl/src/non-ascii.h
new file mode 100644
index 0000000000..8b4b7c22e8
--- /dev/null
+++ b/libs/libcurl/src/non-ascii.h
@@ -0,0 +1,63 @@
+#ifndef HEADER_CURL_NON_ASCII_H
+#define HEADER_CURL_NON_ASCII_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 CURL_DOES_CONVERSIONS
+
+#include "urldata.h"
+
+/*
+ * Curl_convert_clone() returns a malloced copy of the source string (if
+ * returning CURLE_OK), with the data converted to network format.
+ *
+ * If no conversion was needed *outbuf may be NULL.
+ */
+CURLcode Curl_convert_clone(struct SessionHandle *data,
+ const char *indata,
+ size_t insize,
+ char **outbuf);
+
+void Curl_convert_init(struct SessionHandle *data);
+void Curl_convert_setup(struct SessionHandle *data);
+void Curl_convert_close(struct SessionHandle *data);
+
+CURLcode Curl_convert_to_network(struct SessionHandle *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_from_network(struct SessionHandle *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_from_utf8(struct SessionHandle *data,
+ char *buffer, size_t length);
+CURLcode Curl_convert_form(struct SessionHandle *data, struct FormData *form);
+#else
+#define Curl_convert_clone(a,b,c,d) ((void)a, CURLE_OK)
+#define Curl_convert_init(x) Curl_nop_stmt
+#define Curl_convert_setup(x) Curl_nop_stmt
+#define Curl_convert_close(x) Curl_nop_stmt
+#define Curl_convert_to_network(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_from_network(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_from_utf8(a,b,c) ((void)a, CURLE_OK)
+#define Curl_convert_form(a,b) CURLE_OK
+#endif
+
+#endif /* HEADER_CURL_NON_ASCII_H */
diff --git a/libs/libcurl/src/nonblock.c b/libs/libcurl/src/nonblock.c
new file mode 100644
index 0000000000..1447c877df
--- /dev/null
+++ b/libs/libcurl/src/nonblock.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#if (defined(HAVE_IOCTL_FIONBIO) && defined(NETWARE))
+#include <sys/filio.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#include "nonblock.h"
+
+/*
+ * curlx_nonblock() set the given socket to either blocking or non-blocking
+ * mode based on the 'nonblock' boolean argument. This function is highly
+ * portable.
+ */
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */)
+{
+#if defined(USE_BLOCKING_SOCKETS)
+
+ return 0; /* returns success */
+
+#elif defined(HAVE_FCNTL_O_NONBLOCK)
+
+ /* most recent unix versions */
+ int flags;
+ flags = sfcntl(sockfd, F_GETFL, 0);
+ if(nonblock)
+ return sfcntl(sockfd, F_SETFL, flags | O_NONBLOCK);
+ else
+ return sfcntl(sockfd, F_SETFL, flags & (~O_NONBLOCK));
+
+#elif defined(HAVE_IOCTL_FIONBIO)
+
+ /* older unix versions */
+ int flags = nonblock ? 1 : 0;
+ return ioctl(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_FIONBIO)
+
+ /* Windows */
+ unsigned long flags = nonblock ? 1UL : 0UL;
+ return ioctlsocket(sockfd, FIONBIO, &flags);
+
+#elif defined(HAVE_IOCTLSOCKET_CAMEL_FIONBIO)
+
+ /* Amiga */
+ long flags = nonblock ? 1L : 0L;
+ return IoctlSocket(sockfd, FIONBIO, flags);
+
+#elif defined(HAVE_SETSOCKOPT_SO_NONBLOCK)
+
+ /* BeOS */
+ long b = nonblock ? 1L : 0L;
+ return setsockopt(sockfd, SOL_SOCKET, SO_NONBLOCK, &b, sizeof(b));
+
+#else
+# error "no non-blocking method was found/used/set"
+#endif
+}
diff --git a/libs/libcurl/src/nonblock.h b/libs/libcurl/src/nonblock.h
new file mode 100644
index 0000000000..b540ae46f6
--- /dev/null
+++ b/libs/libcurl/src/nonblock.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_NONBLOCK_H
+#define HEADER_CURL_NONBLOCK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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/curl.h> /* for curl_socket_t */
+
+int curlx_nonblock(curl_socket_t sockfd, /* operate on this */
+ int nonblock /* TRUE or FALSE */);
+
+#endif /* HEADER_CURL_NONBLOCK_H */
+
diff --git a/libs/libcurl/src/nss.c b/libs/libcurl/src/nss.c
new file mode 100644
index 0000000000..2d4bf9e9c8
--- /dev/null
+++ b/libs/libcurl/src/nss.c
@@ -0,0 +1,1574 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all NSS-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_NSS
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "connect.h"
+#include "strequal.h"
+#include "select.h"
+#include "sslgen.h"
+#include "llist.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#include "nssg.h"
+#include <nspr.h>
+#include <nss.h>
+#include <ssl.h>
+#include <sslerr.h>
+#include <secerr.h>
+#include <secmod.h>
+#include <sslproto.h>
+#include <prtypes.h>
+#include <pk11pub.h>
+#include <prio.h>
+#include <secitem.h>
+#include <secport.h>
+#include <certdb.h>
+#include <base64.h>
+#include <cert.h>
+#include <prerror.h>
+
+#include "curl_memory.h"
+#include "rawstr.h"
+#include "warnless.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define SSL_DIR "/etc/pki/nssdb"
+
+/* enough to fit the string "PEM Token #[0|1]" */
+#define SLOTSIZE 13
+
+PRFileDesc *PR_ImportTCPSocket(PRInt32 osfd);
+
+PRLock * nss_initlock = NULL;
+PRLock * nss_crllock = NULL;
+#ifdef HAVE_NSS_INITCONTEXT
+NSSInitContext * nss_context = NULL;
+#endif
+
+volatile int initialized = 0;
+
+typedef struct {
+ const char *name;
+ int num;
+} cipher_s;
+
+#define PK11_SETATTRS(_attr, _idx, _type, _val, _len) do { \
+ CK_ATTRIBUTE *ptr = (_attr) + ((_idx)++); \
+ ptr->type = (_type); \
+ ptr->pValue = (_val); \
+ ptr->ulValueLen = (_len); \
+} WHILE_FALSE
+
+#define CERT_NewTempCertificate __CERT_NewTempCertificate
+
+#define NUM_OF_CIPHERS sizeof(cipherlist)/sizeof(cipherlist[0])
+static const cipher_s cipherlist[] = {
+ /* SSL2 cipher suites */
+ {"rc4", SSL_EN_RC4_128_WITH_MD5},
+ {"rc4-md5", SSL_EN_RC4_128_WITH_MD5},
+ {"rc4export", SSL_EN_RC4_128_EXPORT40_WITH_MD5},
+ {"rc2", SSL_EN_RC2_128_CBC_WITH_MD5},
+ {"rc2export", SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5},
+ {"des", SSL_EN_DES_64_CBC_WITH_MD5},
+ {"desede3", SSL_EN_DES_192_EDE3_CBC_WITH_MD5},
+ /* SSL3/TLS cipher suites */
+ {"rsa_rc4_128_md5", SSL_RSA_WITH_RC4_128_MD5},
+ {"rsa_rc4_128_sha", SSL_RSA_WITH_RC4_128_SHA},
+ {"rsa_3des_sha", SSL_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"rsa_des_sha", SSL_RSA_WITH_DES_CBC_SHA},
+ {"rsa_rc4_40_md5", SSL_RSA_EXPORT_WITH_RC4_40_MD5},
+ {"rsa_rc2_40_md5", SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5},
+ {"rsa_null_md5", SSL_RSA_WITH_NULL_MD5},
+ {"rsa_null_sha", SSL_RSA_WITH_NULL_SHA},
+ {"fips_3des_sha", SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA},
+ {"fips_des_sha", SSL_RSA_FIPS_WITH_DES_CBC_SHA},
+ {"fortezza", SSL_FORTEZZA_DMS_WITH_FORTEZZA_CBC_SHA},
+ {"fortezza_rc4_128_sha", SSL_FORTEZZA_DMS_WITH_RC4_128_SHA},
+ {"fortezza_null", SSL_FORTEZZA_DMS_WITH_NULL_SHA},
+ /* TLS 1.0: Exportable 56-bit Cipher Suites. */
+ {"rsa_des_56_sha", TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA},
+ {"rsa_rc4_56_sha", TLS_RSA_EXPORT1024_WITH_RC4_56_SHA},
+ /* AES ciphers. */
+ {"rsa_aes_128_sha", TLS_RSA_WITH_AES_128_CBC_SHA},
+ {"rsa_aes_256_sha", TLS_RSA_WITH_AES_256_CBC_SHA},
+#ifdef NSS_ENABLE_ECC
+ /* ECC ciphers. */
+ {"ecdh_ecdsa_null_sha", TLS_ECDH_ECDSA_WITH_NULL_SHA},
+ {"ecdh_ecdsa_rc4_128_sha", TLS_ECDH_ECDSA_WITH_RC4_128_SHA},
+ {"ecdh_ecdsa_3des_sha", TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_ecdsa_aes_128_sha", TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ecdh_ecdsa_aes_256_sha", TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ecdhe_ecdsa_null_sha", TLS_ECDHE_ECDSA_WITH_NULL_SHA},
+ {"ecdhe_ecdsa_rc4_128_sha", TLS_ECDHE_ECDSA_WITH_RC4_128_SHA},
+ {"ecdhe_ecdsa_3des_sha", TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdhe_ecdsa_aes_128_sha", TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA},
+ {"ecdhe_ecdsa_aes_256_sha", TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+ {"ecdh_rsa_null_sha", TLS_ECDH_RSA_WITH_NULL_SHA},
+ {"ecdh_rsa_128_sha", TLS_ECDH_RSA_WITH_RC4_128_SHA},
+ {"ecdh_rsa_3des_sha", TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_rsa_aes_128_sha", TLS_ECDH_RSA_WITH_AES_128_CBC_SHA},
+ {"ecdh_rsa_aes_256_sha", TLS_ECDH_RSA_WITH_AES_256_CBC_SHA},
+ {"echde_rsa_null", TLS_ECDHE_RSA_WITH_NULL_SHA},
+ {"ecdhe_rsa_rc4_128_sha", TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ {"ecdhe_rsa_3des_sha", TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA},
+ {"ecdhe_rsa_aes_128_sha", TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ {"ecdhe_rsa_aes_256_sha", TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ {"ecdh_anon_null_sha", TLS_ECDH_anon_WITH_NULL_SHA},
+ {"ecdh_anon_rc4_128sha", TLS_ECDH_anon_WITH_RC4_128_SHA},
+ {"ecdh_anon_3des_sha", TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA},
+ {"ecdh_anon_aes_128_sha", TLS_ECDH_anon_WITH_AES_128_CBC_SHA},
+ {"ecdh_anon_aes_256_sha", TLS_ECDH_anon_WITH_AES_256_CBC_SHA},
+#endif
+};
+
+/* following ciphers are new in NSS 3.4 and not enabled by default, therefore
+ they are enabled explicitly */
+static const int enable_ciphers_by_default[] = {
+ TLS_DHE_DSS_WITH_AES_128_CBC_SHA,
+ TLS_DHE_DSS_WITH_AES_256_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_DHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ SSL_NULL_WITH_NULL_NULL
+};
+
+static const char* pem_library = "libnsspem.so";
+SECMODModule* mod = NULL;
+
+static const char* nss_error_to_name(PRErrorCode code)
+{
+ const char *name = PR_ErrorToName(code);
+ if(name)
+ return name;
+
+ return "unknown error";
+}
+
+static void nss_print_error_message(struct SessionHandle *data, PRUint32 err)
+{
+ failf(data, "%s", PR_ErrorToString(err, PR_LANGUAGE_I_DEFAULT));
+}
+
+static SECStatus set_ciphers(struct SessionHandle *data, PRFileDesc * model,
+ char *cipher_list)
+{
+ unsigned int i;
+ PRBool cipher_state[NUM_OF_CIPHERS];
+ PRBool found;
+ char *cipher;
+ SECStatus rv;
+
+ /* First disable all ciphers. This uses a different max value in case
+ * NSS adds more ciphers later we don't want them available by
+ * accident
+ */
+ for(i=0; i<SSL_NumImplementedCiphers; i++) {
+ SSL_CipherPrefSet(model, SSL_ImplementedCiphers[i], SSL_NOT_ALLOWED);
+ }
+
+ /* Set every entry in our list to false */
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ cipher_state[i] = PR_FALSE;
+ }
+
+ cipher = cipher_list;
+
+ while(cipher_list && (cipher_list[0])) {
+ while((*cipher) && (ISSPACE(*cipher)))
+ ++cipher;
+
+ if((cipher_list = strchr(cipher, ','))) {
+ *cipher_list++ = '\0';
+ }
+
+ found = PR_FALSE;
+
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ if(Curl_raw_equal(cipher, cipherlist[i].name)) {
+ cipher_state[i] = PR_TRUE;
+ found = PR_TRUE;
+ break;
+ }
+ }
+
+ if(found == PR_FALSE) {
+ failf(data, "Unknown cipher in list: %s", cipher);
+ return SECFailure;
+ }
+
+ if(cipher_list) {
+ cipher = cipher_list;
+ }
+ }
+
+ /* Finally actually enable the selected ciphers */
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ rv = SSL_CipherPrefSet(model, cipherlist[i].num, cipher_state[i]);
+ if(rv != SECSuccess) {
+ failf(data, "cipher-suite not supported by NSS: %s", cipherlist[i].name);
+ return SECFailure;
+ }
+ }
+
+ return SECSuccess;
+}
+
+/*
+ * Get the number of ciphers that are enabled. We use this to determine
+ * if we need to call NSS_SetDomesticPolicy() to enable the default ciphers.
+ */
+static int num_enabled_ciphers(void)
+{
+ PRInt32 policy = 0;
+ int count = 0;
+ unsigned int i;
+
+ for(i=0; i<NUM_OF_CIPHERS; i++) {
+ SSL_CipherPolicyGet(cipherlist[i].num, &policy);
+ if(policy)
+ count++;
+ }
+ return count;
+}
+
+/*
+ * 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 (NSS nickname)
+ */
+static int is_file(const char *filename)
+{
+ struct_stat st;
+
+ if(filename == NULL)
+ return 0;
+
+ if(stat(filename, &st) == 0)
+ if(S_ISREG(st.st_mode))
+ return 1;
+
+ return 0;
+}
+
+/* Check if the given string is filename or nickname of a certificate. If the
+ * given string is recognized as filename, return NULL. If the given string is
+ * recognized as nickname, return a duplicated string. The returned string
+ * should be later deallocated using free(). If the OOM failure occurs, we
+ * return NULL, too.
+ */
+static char* dup_nickname(struct SessionHandle *data, enum dupstring cert_kind)
+{
+ const char *str = data->set.str[cert_kind];
+ const char *n;
+
+ if(!is_file(str))
+ /* no such file exists, use the string as nickname */
+ return strdup(str);
+
+ /* search the last slash; we require at least one slash in a file name */
+ n = strrchr(str, '/');
+ if(!n) {
+ infof(data, "warning: certificate file name \"%s\" handled as nickname; "
+ "please use \"./%s\" to force file name\n", str, str);
+ return strdup(str);
+ }
+
+ /* we'll use the PEM reader to read the certificate from file */
+ return NULL;
+}
+
+/* Call PK11_CreateGenericObject() with the given obj_class and filename. If
+ * the call succeeds, append the object handle to the list of objects so that
+ * the object can be destroyed in Curl_nss_close(). */
+static CURLcode nss_create_object(struct ssl_connect_data *ssl,
+ CK_OBJECT_CLASS obj_class,
+ const char *filename, bool cacert)
+{
+ PK11SlotInfo *slot;
+ PK11GenericObject *obj;
+ CK_BBOOL cktrue = CK_TRUE;
+ CK_BBOOL ckfalse = CK_FALSE;
+ CK_ATTRIBUTE attrs[/* max count of attributes */ 4];
+ int attr_cnt = 0;
+ CURLcode err = (cacert)
+ ? CURLE_SSL_CACERT_BADFILE
+ : CURLE_SSL_CERTPROBLEM;
+
+ const int slot_id = (cacert) ? 0 : 1;
+ char *slot_name = aprintf("PEM Token #%d", slot_id);
+ if(!slot_name)
+ return CURLE_OUT_OF_MEMORY;
+
+ slot = PK11_FindSlotByName(slot_name);
+ free(slot_name);
+ if(!slot)
+ return err;
+
+ PK11_SETATTRS(attrs, attr_cnt, CKA_CLASS, &obj_class, sizeof(obj_class));
+ PK11_SETATTRS(attrs, attr_cnt, CKA_TOKEN, &cktrue, sizeof(CK_BBOOL));
+ PK11_SETATTRS(attrs, attr_cnt, CKA_LABEL, (unsigned char *)filename,
+ strlen(filename) + 1);
+
+ if(CKO_CERTIFICATE == obj_class) {
+ CK_BBOOL *pval = (cacert) ? (&cktrue) : (&ckfalse);
+ PK11_SETATTRS(attrs, attr_cnt, CKA_TRUST, pval, sizeof(*pval));
+ }
+
+ obj = PK11_CreateGenericObject(slot, attrs, attr_cnt, PR_FALSE);
+ PK11_FreeSlot(slot);
+ if(!obj)
+ return err;
+
+ if(!Curl_llist_insert_next(ssl->obj_list, ssl->obj_list->tail, obj)) {
+ PK11_DestroyGenericObject(obj);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!cacert && CKO_CERTIFICATE == obj_class)
+ /* store reference to a client certificate */
+ ssl->obj_clicert = obj;
+
+ return CURLE_OK;
+}
+
+/* Destroy the NSS object whose handle is given by ptr. This function is
+ * a callback of Curl_llist_alloc() used by Curl_llist_destroy() to destroy
+ * NSS objects in Curl_nss_close() */
+static void nss_destroy_object(void *user, void *ptr)
+{
+ PK11GenericObject *obj = (PK11GenericObject *)ptr;
+ (void) user;
+ PK11_DestroyGenericObject(obj);
+}
+
+static CURLcode nss_load_cert(struct ssl_connect_data *ssl,
+ const char *filename, PRBool cacert)
+{
+ CURLcode err = (cacert)
+ ? CURLE_SSL_CACERT_BADFILE
+ : CURLE_SSL_CERTPROBLEM;
+
+ /* libnsspem.so leaks memory if the requested file does not exist. For more
+ * details, go to <https://bugzilla.redhat.com/734760>. */
+ if(is_file(filename))
+ err = nss_create_object(ssl, CKO_CERTIFICATE, filename, cacert);
+
+ if(CURLE_OK == err && !cacert) {
+ /* we have successfully loaded a client certificate */
+ CERTCertificate *cert;
+ char *nickname = NULL;
+ char *n = strrchr(filename, '/');
+ if(n)
+ n++;
+
+ /* The following undocumented magic helps to avoid a SIGSEGV on call
+ * of PK11_ReadRawAttribute() from SelectClientCert() when using an
+ * immature version of libnsspem.so. For more details, go to
+ * <https://bugzilla.redhat.com/733685>. */
+ nickname = aprintf("PEM Token #1:%s", n);
+ if(nickname) {
+ cert = PK11_FindCertFromNickname(nickname, NULL);
+ if(cert)
+ CERT_DestroyCertificate(cert);
+
+ free(nickname);
+ }
+ }
+
+ return err;
+}
+
+/* add given CRL to cache if it is not already there */
+static SECStatus nss_cache_crl(SECItem *crlDER)
+{
+ CERTCertDBHandle *db = CERT_GetDefaultCertDB();
+ CERTSignedCrl *crl = SEC_FindCrlByDERCert(db, crlDER, 0);
+ if(crl) {
+ /* CRL already cached */
+ SEC_DestroyCrl(crl);
+ SECITEM_FreeItem(crlDER, PR_FALSE);
+ return SECSuccess;
+ }
+
+ /* acquire lock before call of CERT_CacheCRL() */
+ PR_Lock(nss_crllock);
+ if(SECSuccess != CERT_CacheCRL(db, crlDER)) {
+ /* unable to cache CRL */
+ PR_Unlock(nss_crllock);
+ SECITEM_FreeItem(crlDER, PR_FALSE);
+ return SECFailure;
+ }
+
+ /* we need to clear session cache, so that the CRL could take effect */
+ SSL_ClearSessionCache();
+ PR_Unlock(nss_crllock);
+ return SECSuccess;
+}
+
+static SECStatus nss_load_crl(const char* crlfilename)
+{
+ PRFileDesc *infile;
+ PRFileInfo info;
+ SECItem filedata = { 0, NULL, 0 };
+ SECItem crlDER = { 0, NULL, 0 };
+ char *body;
+
+ infile = PR_Open(crlfilename, PR_RDONLY, 0);
+ if(!infile)
+ return SECFailure;
+
+ if(PR_SUCCESS != PR_GetOpenFileInfo(infile, &info))
+ goto fail;
+
+ if(!SECITEM_AllocItem(NULL, &filedata, info.size + /* zero ended */ 1))
+ goto fail;
+
+ if(info.size != PR_Read(infile, filedata.data, info.size))
+ goto fail;
+
+ /* place a trailing zero right after the visible data */
+ body = (char*)filedata.data;
+ body[--filedata.len] = '\0';
+
+ body = strstr(body, "-----BEGIN");
+ if(body) {
+ /* assume ASCII */
+ char *trailer;
+ char *begin = PORT_Strchr(body, '\n');
+ if(!begin)
+ begin = PORT_Strchr(body, '\r');
+ if(!begin)
+ goto fail;
+
+ trailer = strstr(++begin, "-----END");
+ if(!trailer)
+ goto fail;
+
+ /* retrieve DER from ASCII */
+ *trailer = '\0';
+ if(ATOB_ConvertAsciiToItem(&crlDER, begin))
+ goto fail;
+
+ SECITEM_FreeItem(&filedata, PR_FALSE);
+ }
+ else
+ /* assume DER */
+ crlDER = filedata;
+
+ PR_Close(infile);
+ return nss_cache_crl(&crlDER);
+
+fail:
+ PR_Close(infile);
+ SECITEM_FreeItem(&filedata, PR_FALSE);
+ return SECFailure;
+}
+
+static CURLcode nss_load_key(struct connectdata *conn, int sockindex,
+ char *key_file)
+{
+ PK11SlotInfo *slot;
+ SECStatus status;
+ CURLcode rv;
+ struct ssl_connect_data *ssl = conn->ssl;
+ (void)sockindex; /* unused */
+
+ rv = nss_create_object(ssl, CKO_PRIVATE_KEY, key_file, FALSE);
+ if(CURLE_OK != rv) {
+ PR_SetError(SEC_ERROR_BAD_KEY, 0);
+ return rv;
+ }
+
+ slot = PK11_FindSlotByName("PEM Token #1");
+ if(!slot)
+ return CURLE_SSL_CERTPROBLEM;
+
+ /* This will force the token to be seen as re-inserted */
+ SECMOD_WaitForAnyTokenEvent(mod, 0, 0);
+ PK11_IsPresent(slot);
+
+ status = PK11_Authenticate(slot, PR_TRUE,
+ conn->data->set.str[STRING_KEY_PASSWD]);
+ PK11_FreeSlot(slot);
+ return (SECSuccess == status)
+ ? CURLE_OK
+ : CURLE_SSL_CERTPROBLEM;
+}
+
+static int display_error(struct connectdata *conn, PRInt32 err,
+ const char *filename)
+{
+ switch(err) {
+ case SEC_ERROR_BAD_PASSWORD:
+ failf(conn->data, "Unable to load client key: Incorrect password");
+ return 1;
+ case SEC_ERROR_UNKNOWN_CERT:
+ failf(conn->data, "Unable to load certificate %s", filename);
+ return 1;
+ default:
+ break;
+ }
+ return 0; /* The caller will print a generic error */
+}
+
+static CURLcode cert_stuff(struct connectdata *conn, int sockindex,
+ char *cert_file, char *key_file)
+{
+ struct SessionHandle *data = conn->data;
+ CURLcode rv;
+
+ if(cert_file) {
+ rv = nss_load_cert(&conn->ssl[sockindex], cert_file, PR_FALSE);
+ if(CURLE_OK != rv) {
+ const PRErrorCode err = PR_GetError();
+ if(!display_error(conn, err, cert_file)) {
+ const char *err_name = nss_error_to_name(err);
+ failf(data, "unable to load client cert: %d (%s)", err, err_name);
+ }
+
+ return rv;
+ }
+ }
+
+ if(key_file || (is_file(cert_file))) {
+ if(key_file)
+ rv = nss_load_key(conn, sockindex, key_file);
+ else
+ /* In case the cert file also has the key */
+ rv = nss_load_key(conn, sockindex, cert_file);
+ if(CURLE_OK != rv) {
+ const PRErrorCode err = PR_GetError();
+ if(!display_error(conn, err, key_file)) {
+ const char *err_name = nss_error_to_name(err);
+ failf(data, "unable to load client key: %d (%s)", err, err_name);
+ }
+
+ return rv;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static char * nss_get_password(PK11SlotInfo * slot, PRBool retry, void *arg)
+{
+ (void)slot; /* unused */
+ if(retry || NULL == arg)
+ return NULL;
+ else
+ return (char *)PORT_Strdup((char *)arg);
+}
+
+/* bypass the default SSL_AuthCertificate() hook in case we do not want to
+ * verify peer */
+static SECStatus nss_auth_cert_hook(void *arg, PRFileDesc *fd, PRBool checksig,
+ PRBool isServer)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ if(!conn->data->set.ssl.verifypeer) {
+ infof(conn->data, "skipping SSL peer certificate verification\n");
+ return SECSuccess;
+ }
+
+ return SSL_AuthCertificate(CERT_GetDefaultCertDB(), fd, checksig, isServer);
+}
+
+/**
+ * Inform the application that the handshake is complete.
+ */
+static void HandshakeCallback(PRFileDesc *sock, void *arg)
+{
+ (void)sock;
+ (void)arg;
+}
+
+static void display_cert_info(struct SessionHandle *data,
+ CERTCertificate *cert)
+{
+ char *subject, *issuer, *common_name;
+ PRExplodedTime printableTime;
+ char timeString[256];
+ PRTime notBefore, notAfter;
+
+ subject = CERT_NameToAscii(&cert->subject);
+ issuer = CERT_NameToAscii(&cert->issuer);
+ common_name = CERT_GetCommonName(&cert->subject);
+ infof(data, "\tsubject: %s\n", subject);
+
+ CERT_GetCertTimes(cert, &notBefore, &notAfter);
+ PR_ExplodeTime(notBefore, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(data, "\tstart date: %s\n", timeString);
+ PR_ExplodeTime(notAfter, PR_GMTParameters, &printableTime);
+ PR_FormatTime(timeString, 256, "%b %d %H:%M:%S %Y GMT", &printableTime);
+ infof(data, "\texpire date: %s\n", timeString);
+ infof(data, "\tcommon name: %s\n", common_name);
+ infof(data, "\tissuer: %s\n", issuer);
+
+ PR_Free(subject);
+ PR_Free(issuer);
+ PR_Free(common_name);
+}
+
+static void display_conn_info(struct connectdata *conn, PRFileDesc *sock)
+{
+ SSLChannelInfo channel;
+ SSLCipherSuiteInfo suite;
+ CERTCertificate *cert;
+
+ if(SSL_GetChannelInfo(sock, &channel, sizeof channel) ==
+ SECSuccess && channel.length == sizeof channel &&
+ channel.cipherSuite) {
+ if(SSL_GetCipherSuiteInfo(channel.cipherSuite,
+ &suite, sizeof suite) == SECSuccess) {
+ infof(conn->data, "SSL connection using %s\n", suite.cipherSuiteName);
+ }
+ }
+
+ infof(conn->data, "Server certificate:\n");
+
+ cert = SSL_PeerCertificate(sock);
+ display_cert_info(conn->data, cert);
+ CERT_DestroyCertificate(cert);
+
+ return;
+}
+
+static SECStatus BadCertHandler(void *arg, PRFileDesc *sock)
+{
+ struct connectdata *conn = (struct connectdata *)arg;
+ struct SessionHandle *data = conn->data;
+ PRErrorCode err = PR_GetError();
+ CERTCertificate *cert;
+
+ /* remember the cert verification result */
+ data->set.ssl.certverifyresult = err;
+
+ if(err == SSL_ERROR_BAD_CERT_DOMAIN && !data->set.ssl.verifyhost)
+ /* we are asked not to verify the host name */
+ return SECSuccess;
+
+ /* print only info about the cert, the error is printed off the callback */
+ cert = SSL_PeerCertificate(sock);
+ if(cert) {
+ infof(data, "Server certificate:\n");
+ display_cert_info(data, cert);
+ CERT_DestroyCertificate(cert);
+ }
+
+ return SECFailure;
+}
+
+/**
+ *
+ * Check that the Peer certificate's issuer certificate matches the one found
+ * by issuer_nickname. This is not exactly the way OpenSSL and GNU TLS do the
+ * issuer check, so we provide comments that mimic the OpenSSL
+ * X509_check_issued function (in x509v3/v3_purp.c)
+ */
+static SECStatus check_issuer_cert(PRFileDesc *sock,
+ char *issuer_nickname)
+{
+ CERTCertificate *cert,*cert_issuer,*issuer;
+ SECStatus res=SECSuccess;
+ void *proto_win = NULL;
+
+ /*
+ PRArenaPool *tmpArena = NULL;
+ CERTAuthKeyID *authorityKeyID = NULL;
+ SECITEM *caname = NULL;
+ */
+
+ cert = SSL_PeerCertificate(sock);
+ cert_issuer = CERT_FindCertIssuer(cert,PR_Now(),certUsageObjectSigner);
+
+ proto_win = SSL_RevealPinArg(sock);
+ issuer = PK11_FindCertFromNickname(issuer_nickname, proto_win);
+
+ if((!cert_issuer) || (!issuer))
+ res = SECFailure;
+ else if(SECITEM_CompareItem(&cert_issuer->derCert,
+ &issuer->derCert)!=SECEqual)
+ res = SECFailure;
+
+ CERT_DestroyCertificate(cert);
+ CERT_DestroyCertificate(issuer);
+ CERT_DestroyCertificate(cert_issuer);
+ return res;
+}
+
+/**
+ *
+ * Callback to pick the SSL client certificate.
+ */
+static SECStatus SelectClientCert(void *arg, PRFileDesc *sock,
+ struct CERTDistNamesStr *caNames,
+ struct CERTCertificateStr **pRetCert,
+ struct SECKEYPrivateKeyStr **pRetKey)
+{
+ struct ssl_connect_data *connssl = (struct ssl_connect_data *)arg;
+ struct SessionHandle *data = connssl->data;
+ const char *nickname = connssl->client_nickname;
+
+ if(connssl->obj_clicert) {
+ /* use the cert/key provided by PEM reader */
+ static const char pem_slotname[] = "PEM Token #1";
+ SECItem cert_der = { 0, NULL, 0 };
+ void *proto_win = SSL_RevealPinArg(sock);
+ struct CERTCertificateStr *cert;
+ struct SECKEYPrivateKeyStr *key;
+
+ PK11SlotInfo *slot = PK11_FindSlotByName(pem_slotname);
+ if(NULL == slot) {
+ failf(data, "NSS: PK11 slot not found: %s", pem_slotname);
+ return SECFailure;
+ }
+
+ if(PK11_ReadRawAttribute(PK11_TypeGeneric, connssl->obj_clicert, CKA_VALUE,
+ &cert_der) != SECSuccess) {
+ failf(data, "NSS: CKA_VALUE not found in PK11 generic object");
+ PK11_FreeSlot(slot);
+ return SECFailure;
+ }
+
+ cert = PK11_FindCertFromDERCertItem(slot, &cert_der, proto_win);
+ SECITEM_FreeItem(&cert_der, PR_FALSE);
+ if(NULL == cert) {
+ failf(data, "NSS: client certificate from file not found");
+ PK11_FreeSlot(slot);
+ return SECFailure;
+ }
+
+ key = PK11_FindPrivateKeyFromCert(slot, cert, NULL);
+ PK11_FreeSlot(slot);
+ if(NULL == key) {
+ failf(data, "NSS: private key from file not found");
+ CERT_DestroyCertificate(cert);
+ return SECFailure;
+ }
+
+ infof(data, "NSS: client certificate from file\n");
+ display_cert_info(data, cert);
+
+ *pRetCert = cert;
+ *pRetKey = key;
+ return SECSuccess;
+ }
+
+ /* use the default NSS hook */
+ if(SECSuccess != NSS_GetClientAuthData((void *)nickname, sock, caNames,
+ pRetCert, pRetKey)
+ || NULL == *pRetCert) {
+
+ if(NULL == nickname)
+ failf(data, "NSS: client certificate not found (nickname not "
+ "specified)");
+ else
+ failf(data, "NSS: client certificate not found: %s", nickname);
+
+ return SECFailure;
+ }
+
+ /* get certificate nickname if any */
+ nickname = (*pRetCert)->nickname;
+ if(NULL == nickname)
+ nickname = "[unknown]";
+
+ if(NULL == *pRetKey) {
+ failf(data, "NSS: private key not found for certificate: %s", nickname);
+ return SECFailure;
+ }
+
+ infof(data, "NSS: using client certificate: %s\n", nickname);
+ display_cert_info(data, *pRetCert);
+ return SECSuccess;
+}
+
+/* This function is supposed to decide, which error codes should be used
+ * to conclude server is TLS intolerant.
+ *
+ * taken from xulrunner - nsNSSIOLayer.cpp
+ */
+static PRBool
+isTLSIntoleranceError(PRInt32 err)
+{
+ switch (err) {
+ case SSL_ERROR_BAD_MAC_ALERT:
+ case SSL_ERROR_BAD_MAC_READ:
+ case SSL_ERROR_HANDSHAKE_FAILURE_ALERT:
+ case SSL_ERROR_HANDSHAKE_UNEXPECTED_ALERT:
+ case SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE:
+ case SSL_ERROR_ILLEGAL_PARAMETER_ALERT:
+ case SSL_ERROR_NO_CYPHER_OVERLAP:
+ case SSL_ERROR_BAD_SERVER:
+ case SSL_ERROR_BAD_BLOCK_PADDING:
+ case SSL_ERROR_UNSUPPORTED_VERSION:
+ case SSL_ERROR_PROTOCOL_VERSION_ALERT:
+ case SSL_ERROR_RX_MALFORMED_FINISHED:
+ case SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE:
+ case SSL_ERROR_DECODE_ERROR_ALERT:
+ case SSL_ERROR_RX_UNKNOWN_ALERT:
+ return PR_TRUE;
+ default:
+ return PR_FALSE;
+ }
+}
+
+static CURLcode nss_init_core(struct SessionHandle *data, const char *cert_dir)
+{
+#ifdef HAVE_NSS_INITCONTEXT
+ NSSInitParameters initparams;
+
+ if(nss_context != NULL)
+ return CURLE_OK;
+
+ memset((void *) &initparams, '\0', sizeof(initparams));
+ initparams.length = sizeof(initparams);
+#else /* HAVE_NSS_INITCONTEXT */
+ SECStatus rv;
+
+ if(NSS_IsInitialized())
+ return CURLE_OK;
+#endif
+
+ if(cert_dir) {
+ const bool use_sql = NSS_VersionCheck("3.12.0");
+ char *certpath = aprintf("%s%s", use_sql ? "sql:" : "", cert_dir);
+ if(!certpath)
+ return CURLE_OUT_OF_MEMORY;
+
+ infof(data, "Initializing NSS with certpath: %s\n", certpath);
+#ifdef HAVE_NSS_INITCONTEXT
+ nss_context = NSS_InitContext(certpath, "", "", "", &initparams,
+ NSS_INIT_READONLY | NSS_INIT_PK11RELOAD);
+ free(certpath);
+
+ if(nss_context != NULL)
+ return CURLE_OK;
+#else /* HAVE_NSS_INITCONTEXT */
+ rv = NSS_Initialize(certpath, "", "", "", NSS_INIT_READONLY);
+ free(certpath);
+
+ if(rv == SECSuccess)
+ return CURLE_OK;
+#endif
+
+ infof(data, "Unable to initialize NSS database\n");
+ }
+
+ infof(data, "Initializing NSS with certpath: none\n");
+#ifdef HAVE_NSS_INITCONTEXT
+ nss_context = NSS_InitContext("", "", "", "", &initparams, NSS_INIT_READONLY
+ | NSS_INIT_NOCERTDB | NSS_INIT_NOMODDB | NSS_INIT_FORCEOPEN
+ | NSS_INIT_NOROOTINIT | NSS_INIT_OPTIMIZESPACE | NSS_INIT_PK11RELOAD);
+ if(nss_context != NULL)
+ return CURLE_OK;
+#else /* HAVE_NSS_INITCONTEXT */
+ if(NSS_NoDB_Init(NULL) == SECSuccess)
+ return CURLE_OK;
+#endif
+
+ infof(data, "Unable to initialize NSS\n");
+ return CURLE_SSL_CACERT_BADFILE;
+}
+
+static CURLcode nss_init(struct SessionHandle *data)
+{
+ char *cert_dir;
+ struct_stat st;
+ CURLcode rv;
+
+ if(initialized)
+ return CURLE_OK;
+
+ /* First we check if $SSL_DIR points to a valid dir */
+ cert_dir = getenv("SSL_DIR");
+ if(cert_dir) {
+ if((stat(cert_dir, &st) != 0) ||
+ (!S_ISDIR(st.st_mode))) {
+ cert_dir = NULL;
+ }
+ }
+
+ /* Now we check if the default location is a valid dir */
+ if(!cert_dir) {
+ if((stat(SSL_DIR, &st) == 0) &&
+ (S_ISDIR(st.st_mode))) {
+ cert_dir = (char *)SSL_DIR;
+ }
+ }
+
+ rv = nss_init_core(data, cert_dir);
+ if(rv)
+ return rv;
+
+ if(num_enabled_ciphers() == 0)
+ NSS_SetDomesticPolicy();
+
+ initialized = 1;
+ return CURLE_OK;
+}
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_nss_init(void)
+{
+ /* curl_global_init() is not thread-safe so this test is ok */
+ if(nss_initlock == NULL) {
+ PR_Init(PR_USER_THREAD, PR_PRIORITY_NORMAL, 256);
+ nss_initlock = PR_NewLock();
+ nss_crllock = PR_NewLock();
+ }
+
+ /* We will actually initialize NSS later */
+
+ return 1;
+}
+
+CURLcode Curl_nss_force_init(struct SessionHandle *data)
+{
+ CURLcode rv;
+ if(!nss_initlock) {
+ failf(data,
+ "unable to initialize NSS, curl_global_init() should have been "
+ "called with CURL_GLOBAL_SSL or CURL_GLOBAL_ALL");
+ return CURLE_FAILED_INIT;
+ }
+
+ PR_Lock(nss_initlock);
+ rv = nss_init(data);
+ PR_Unlock(nss_initlock);
+ return rv;
+}
+
+/* Global cleanup */
+void Curl_nss_cleanup(void)
+{
+ /* This function isn't required to be threadsafe and this is only done
+ * as a safety feature.
+ */
+ PR_Lock(nss_initlock);
+ if(initialized) {
+ /* Free references to client certificates held in the SSL session cache.
+ * Omitting this hampers destruction of the security module owning
+ * the certificates. */
+ SSL_ClearSessionCache();
+
+ if(mod && SECSuccess == SECMOD_UnloadUserModule(mod)) {
+ SECMOD_DestroyModule(mod);
+ mod = NULL;
+ }
+#ifdef HAVE_NSS_INITCONTEXT
+ NSS_ShutdownContext(nss_context);
+ nss_context = NULL;
+#else /* HAVE_NSS_INITCONTEXT */
+ NSS_Shutdown();
+#endif
+ }
+ PR_Unlock(nss_initlock);
+
+ PR_DestroyLock(nss_initlock);
+ PR_DestroyLock(nss_crllock);
+ nss_initlock = NULL;
+
+ initialized = 0;
+}
+
+/*
+ * This function uses SSL_peek to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int
+Curl_nss_check_cxn(struct connectdata *conn)
+{
+ int rc;
+ char buf;
+
+ rc =
+ PR_Recv(conn->ssl[FIRSTSOCKET].handle, (void *)&buf, 1, PR_MSG_PEEK,
+ PR_SecondsToInterval(1));
+ if(rc > 0)
+ return 1; /* connection still in place */
+
+ if(rc == 0)
+ return 0; /* connection has been closed */
+
+ return -1; /* connection status unknown */
+}
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_nss_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->handle) {
+ /* NSS closes the socket we previously handed to it, so we must mark it
+ as closed to avoid double close */
+ fake_sclose(conn->sock[sockindex]);
+ conn->sock[sockindex] = CURL_SOCKET_BAD;
+
+ if((connssl->client_nickname != NULL) || (connssl->obj_clicert != NULL))
+ /* A server might require different authentication based on the
+ * particular path being requested by the client. To support this
+ * scenario, we must ensure that a connection will never reuse the
+ * authentication data from a previous connection. */
+ SSL_InvalidateSession(connssl->handle);
+
+ if(connssl->client_nickname != NULL) {
+ free(connssl->client_nickname);
+ connssl->client_nickname = NULL;
+ }
+ /* destroy all NSS objects in order to avoid failure of NSS shutdown */
+ Curl_llist_destroy(connssl->obj_list, NULL);
+ connssl->obj_list = NULL;
+ connssl->obj_clicert = NULL;
+
+ PR_Close(connssl->handle);
+ connssl->handle = NULL;
+ }
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+int Curl_nss_close_all(struct SessionHandle *data)
+{
+ (void)data;
+ return 0;
+}
+
+/* return true if NSS can provide error code (and possibly msg) for the
+ error */
+static bool is_nss_error(CURLcode err)
+{
+ switch(err) {
+ case CURLE_PEER_FAILED_VERIFICATION:
+ case CURLE_SSL_CACERT:
+ case CURLE_SSL_CERTPROBLEM:
+ case CURLE_SSL_CONNECT_ERROR:
+ case CURLE_SSL_ISSUER_ERROR:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/* return true if the given error code is related to a client certificate */
+static bool is_cc_error(PRInt32 err)
+{
+ switch(err) {
+ case SSL_ERROR_BAD_CERT_ALERT:
+ case SSL_ERROR_EXPIRED_CERT_ALERT:
+ case SSL_ERROR_REVOKED_CERT_ALERT:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+static Curl_recv nss_recv;
+static Curl_send nss_send;
+
+static CURLcode nss_load_ca_certificates(struct connectdata *conn,
+ int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ const char *cafile = data->set.ssl.CAfile;
+ const char *capath = data->set.ssl.CApath;
+
+ if(cafile) {
+ CURLcode rv = nss_load_cert(&conn->ssl[sockindex], cafile, PR_TRUE);
+ if(CURLE_OK != rv)
+ return rv;
+ }
+
+ if(capath) {
+ struct_stat st;
+ if(stat(capath, &st) == -1)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ if(S_ISDIR(st.st_mode)) {
+ PRDirEntry *entry;
+ PRDir *dir = PR_OpenDir(capath);
+ if(!dir)
+ return CURLE_SSL_CACERT_BADFILE;
+
+ while((entry = PR_ReadDir(dir, PR_SKIP_BOTH | PR_SKIP_HIDDEN))) {
+ char *fullpath = aprintf("%s/%s", capath, entry->name);
+ if(!fullpath) {
+ PR_CloseDir(dir);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(CURLE_OK != nss_load_cert(&conn->ssl[sockindex], fullpath, PR_TRUE))
+ /* This is purposefully tolerant of errors so non-PEM files can
+ * be in the same directory */
+ infof(data, "failed to load '%s' from CURLOPT_CAPATH\n", fullpath);
+
+ free(fullpath);
+ }
+
+ PR_CloseDir(dir);
+ }
+ else
+ infof(data, "warning: CURLOPT_CAPATH not a directory (%s)\n", capath);
+ }
+
+ infof(data, " CAfile: %s\n CApath: %s\n",
+ cafile ? cafile : "none",
+ capath ? capath : "none");
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex)
+{
+ PRErrorCode err = 0;
+ PRFileDesc *model = NULL;
+ PRBool ssl2 = PR_FALSE;
+ PRBool ssl3 = PR_FALSE;
+ PRBool tlsv1 = PR_FALSE;
+ PRBool ssl_no_cache;
+ PRBool ssl_cbc_random_iv;
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ CURLcode curlerr;
+ const int *cipher_to_enable;
+ PRSocketOptionData sock_opt;
+ long time_left;
+ PRUint32 timeout;
+
+ if(connssl->state == ssl_connection_complete)
+ return CURLE_OK;
+
+ connssl->data = data;
+
+ /* list of all NSS objects we need to destroy in Curl_nss_close() */
+ connssl->obj_list = Curl_llist_alloc(nss_destroy_object);
+ if(!connssl->obj_list)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* FIXME. NSS doesn't support multiple databases open at the same time. */
+ PR_Lock(nss_initlock);
+ curlerr = nss_init(conn->data);
+ if(CURLE_OK != curlerr) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
+
+ curlerr = CURLE_SSL_CONNECT_ERROR;
+
+ if(!mod) {
+ char *configstring = aprintf("library=%s name=PEM", pem_library);
+ if(!configstring) {
+ PR_Unlock(nss_initlock);
+ goto error;
+ }
+ mod = SECMOD_LoadUserModule(configstring, NULL, PR_FALSE);
+ free(configstring);
+
+ if(!mod || !mod->loaded) {
+ if(mod) {
+ SECMOD_DestroyModule(mod);
+ mod = NULL;
+ }
+ infof(data, "WARNING: failed to load NSS PEM library %s. Using "
+ "OpenSSL PEM certificates will not work.\n", pem_library);
+ }
+ }
+
+ PK11_SetPasswordFunc(nss_get_password);
+ PR_Unlock(nss_initlock);
+
+ model = PR_NewTCPSocket();
+ if(!model)
+ goto error;
+ model = SSL_ImportFD(NULL, model);
+
+ if(SSL_OptionSet(model, SSL_SECURITY, PR_TRUE) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_SERVER, PR_FALSE) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_HANDSHAKE_AS_CLIENT, PR_TRUE) != SECSuccess)
+ goto error;
+
+ /* do not use SSL cache if we are not going to verify peer */
+ ssl_no_cache = (data->set.ssl.verifypeer) ? PR_FALSE : PR_TRUE;
+ if(SSL_OptionSet(model, SSL_NO_CACHE, ssl_no_cache) != SECSuccess)
+ goto error;
+
+ switch (data->set.ssl.version) {
+ default:
+ case CURL_SSLVERSION_DEFAULT:
+ ssl3 = PR_TRUE;
+ if(data->state.ssl_connect_retry)
+ infof(data, "TLS disabled due to previous handshake failure\n");
+ else
+ tlsv1 = PR_TRUE;
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ tlsv1 = PR_TRUE;
+ break;
+ case CURL_SSLVERSION_SSLv2:
+ ssl2 = PR_TRUE;
+ break;
+ case CURL_SSLVERSION_SSLv3:
+ ssl3 = PR_TRUE;
+ break;
+ }
+
+ if(SSL_OptionSet(model, SSL_ENABLE_SSL2, ssl2) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_ENABLE_SSL3, ssl3) != SECSuccess)
+ goto error;
+ if(SSL_OptionSet(model, SSL_ENABLE_TLS, tlsv1) != SECSuccess)
+ goto error;
+
+ if(SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, ssl2) != SECSuccess)
+ goto error;
+
+ ssl_cbc_random_iv = !data->set.ssl_enable_beast;
+#ifdef SSL_CBC_RANDOM_IV
+ /* unless the user explicitly asks to allow the protocol vulnerability, we
+ use the work-around */
+ if(SSL_OptionSet(model, SSL_CBC_RANDOM_IV, ssl_cbc_random_iv) != SECSuccess)
+ infof(data, "warning: failed to set SSL_CBC_RANDOM_IV = %d\n",
+ ssl_cbc_random_iv);
+#else
+ if(ssl_cbc_random_iv)
+ infof(data, "warning: support for SSL_CBC_RANDOM_IV not compiled in\n");
+#endif
+
+ /* reset the flag to avoid an infinite loop */
+ data->state.ssl_connect_retry = FALSE;
+
+ /* enable all ciphers from enable_ciphers_by_default */
+ cipher_to_enable = enable_ciphers_by_default;
+ while(SSL_NULL_WITH_NULL_NULL != *cipher_to_enable) {
+ if(SSL_CipherPrefSet(model, *cipher_to_enable, PR_TRUE) != SECSuccess) {
+ curlerr = CURLE_SSL_CIPHER;
+ goto error;
+ }
+ cipher_to_enable++;
+ }
+
+ if(data->set.ssl.cipher_list) {
+ if(set_ciphers(data, model, data->set.ssl.cipher_list) != SECSuccess) {
+ curlerr = CURLE_SSL_CIPHER;
+ goto error;
+ }
+ }
+
+ if(!data->set.ssl.verifypeer && data->set.ssl.verifyhost)
+ infof(data, "warning: ignoring value of ssl.verifyhost\n");
+
+ /* bypass the default SSL_AuthCertificate() hook in case we do not want to
+ * verify peer */
+ if(SSL_AuthCertificateHook(model, nss_auth_cert_hook, conn) != SECSuccess)
+ goto error;
+
+ data->set.ssl.certverifyresult=0; /* not checked yet */
+ if(SSL_BadCertHook(model, BadCertHandler, conn) != SECSuccess)
+ goto error;
+
+ if(SSL_HandshakeCallback(model, HandshakeCallback, NULL) != SECSuccess)
+ goto error;
+
+ if(data->set.ssl.verifypeer) {
+ const CURLcode rv = nss_load_ca_certificates(conn, sockindex);
+ if(CURLE_OK != rv) {
+ curlerr = rv;
+ goto error;
+ }
+ }
+
+ if(data->set.ssl.CRLfile) {
+ if(SECSuccess != nss_load_crl(data->set.ssl.CRLfile)) {
+ curlerr = CURLE_SSL_CRL_BADFILE;
+ goto error;
+ }
+ infof(data,
+ " CRLfile: %s\n",
+ data->set.ssl.CRLfile ? data->set.ssl.CRLfile : "none");
+ }
+
+ if(data->set.str[STRING_CERT]) {
+ char *nickname = dup_nickname(data, STRING_CERT);
+ if(nickname) {
+ /* we are not going to use libnsspem.so to read the client cert */
+ connssl->obj_clicert = NULL;
+ }
+ else {
+ CURLcode rv = cert_stuff(conn, sockindex, data->set.str[STRING_CERT],
+ data->set.str[STRING_KEY]);
+ if(CURLE_OK != rv) {
+ /* failf() is already done in cert_stuff() */
+ curlerr = rv;
+ goto error;
+ }
+ }
+
+ /* store the nickname for SelectClientCert() called during handshake */
+ connssl->client_nickname = nickname;
+ }
+ else
+ connssl->client_nickname = NULL;
+
+ if(SSL_GetClientAuthDataHook(model, SelectClientCert,
+ (void *)connssl) != SECSuccess) {
+ curlerr = CURLE_SSL_CERTPROBLEM;
+ goto error;
+ }
+
+ /* Import our model socket onto the existing file descriptor */
+ connssl->handle = PR_ImportTCPSocket(sockfd);
+ connssl->handle = SSL_ImportFD(model, connssl->handle);
+ if(!connssl->handle)
+ goto error;
+
+ PR_Close(model); /* We don't need this any more */
+ model = NULL;
+
+ /* This is the password associated with the cert that we're using */
+ if(data->set.str[STRING_KEY_PASSWD]) {
+ SSL_SetPKCS11PinArg(connssl->handle, data->set.str[STRING_KEY_PASSWD]);
+ }
+
+ /* Force handshake on next I/O */
+ SSL_ResetHandshake(connssl->handle, /* asServer */ PR_FALSE);
+
+ SSL_SetURL(connssl->handle, conn->host.name);
+
+ /* check timeout situation */
+ time_left = Curl_timeleft(data, NULL, TRUE);
+ if(time_left < 0L) {
+ failf(data, "timed out before SSL handshake");
+ curlerr = CURLE_OPERATION_TIMEDOUT;
+ goto error;
+ }
+ timeout = PR_MillisecondsToInterval((PRUint32) time_left);
+
+ /* Force the handshake now */
+ if(SSL_ForceHandshakeWithTimeout(connssl->handle, timeout) != SECSuccess) {
+ if(conn->data->set.ssl.certverifyresult == SSL_ERROR_BAD_CERT_DOMAIN)
+ curlerr = CURLE_PEER_FAILED_VERIFICATION;
+ else if(conn->data->set.ssl.certverifyresult!=0)
+ curlerr = CURLE_SSL_CACERT;
+ goto error;
+ }
+
+ /* switch the SSL socket into non-blocking mode */
+ sock_opt.option = PR_SockOpt_Nonblocking;
+ sock_opt.value.non_blocking = PR_TRUE;
+ if(PR_SetSocketOption(connssl->handle, &sock_opt) != PR_SUCCESS)
+ goto error;
+
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = nss_recv;
+ conn->send[sockindex] = nss_send;
+
+ display_conn_info(conn, connssl->handle);
+
+ if(data->set.str[STRING_SSL_ISSUERCERT]) {
+ SECStatus ret = SECFailure;
+ char *nickname = dup_nickname(data, STRING_SSL_ISSUERCERT);
+ if(nickname) {
+ /* we support only nicknames in case of STRING_SSL_ISSUERCERT for now */
+ ret = check_issuer_cert(connssl->handle, nickname);
+ free(nickname);
+ }
+
+ if(SECFailure == ret) {
+ infof(data,"SSL certificate issuer check failed\n");
+ curlerr = CURLE_SSL_ISSUER_ERROR;
+ goto error;
+ }
+ else {
+ infof(data, "SSL certificate issuer check ok\n");
+ }
+ }
+
+ return CURLE_OK;
+
+ error:
+ /* reset the flag to avoid an infinite loop */
+ data->state.ssl_connect_retry = FALSE;
+
+ if(is_nss_error(curlerr)) {
+ /* read NSPR error code */
+ err = PR_GetError();
+ if(is_cc_error(err))
+ curlerr = CURLE_SSL_CERTPROBLEM;
+
+ /* print the error number and error string */
+ infof(data, "NSS error %d (%s)\n", err, nss_error_to_name(err));
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(data, err);
+ }
+
+ if(model)
+ PR_Close(model);
+
+ /* cleanup on connection failure */
+ Curl_llist_destroy(connssl->obj_list, NULL);
+ connssl->obj_list = NULL;
+
+ if(ssl3 && tlsv1 && isTLSIntoleranceError(err)) {
+ /* schedule reconnect through Curl_retry_request() */
+ data->state.ssl_connect_retry = TRUE;
+ infof(data, "Error in TLS handshake, trying SSLv3...\n");
+ return CURLE_OK;
+ }
+
+ return curlerr;
+}
+
+static ssize_t nss_send(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ const void *mem, /* send this data */
+ size_t len, /* amount to write */
+ CURLcode *curlcode)
+{
+ ssize_t rc = PR_Send(conn->ssl[sockindex].handle, mem, (int)len, 0,
+ PR_INTERVAL_NO_WAIT);
+ if(rc < 0) {
+ PRInt32 err = PR_GetError();
+ if(err == PR_WOULD_BLOCK_ERROR)
+ *curlcode = CURLE_AGAIN;
+ else {
+ /* print the error number and error string */
+ const char *err_name = nss_error_to_name(err);
+ infof(conn->data, "SSL write: error %d (%s)\n", err, err_name);
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(conn->data, err);
+
+ *curlcode = (is_cc_error(err))
+ ? CURLE_SSL_CERTPROBLEM
+ : CURLE_SEND_ERROR;
+ }
+ return -1;
+ }
+ return rc; /* number of bytes */
+}
+
+static ssize_t nss_recv(struct connectdata * conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ ssize_t nread = PR_Recv(conn->ssl[num].handle, buf, (int)buffersize, 0,
+ PR_INTERVAL_NO_WAIT);
+ if(nread < 0) {
+ /* failed SSL read */
+ PRInt32 err = PR_GetError();
+
+ if(err == PR_WOULD_BLOCK_ERROR)
+ *curlcode = CURLE_AGAIN;
+ else {
+ /* print the error number and error string */
+ const char *err_name = nss_error_to_name(err);
+ infof(conn->data, "SSL read: errno %d (%s)\n", err, err_name);
+
+ /* print a human-readable message describing the error if available */
+ nss_print_error_message(conn->data, err);
+
+ *curlcode = (is_cc_error(err))
+ ? CURLE_SSL_CERTPROBLEM
+ : CURLE_RECV_ERROR;
+ }
+ return -1;
+ }
+ return nread;
+}
+
+size_t Curl_nss_version(char *buffer, size_t size)
+{
+ return snprintf(buffer, size, "NSS/%s", NSS_VERSION);
+}
+
+int Curl_nss_seed(struct SessionHandle *data)
+{
+ /* make sure that NSS is initialized */
+ return !!Curl_nss_force_init(data);
+}
+
+void Curl_nss_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ Curl_nss_seed(data); /* Initiate the seed if not already done */
+ if(SECSuccess != PK11_GenerateRandom(entropy, curlx_uztosi(length))) {
+ /* no way to signal a failure from here, we have to abort */
+ failf(data, "PK11_GenerateRandom() failed, calling abort()...");
+ abort();
+ }
+}
+
+void Curl_nss_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+ PK11Context *MD5pw = PK11_CreateDigestContext(SEC_OID_MD5);
+ unsigned int MD5out;
+ PK11_DigestOp(MD5pw, tmp, curlx_uztoui(tmplen));
+ PK11_DigestFinal(MD5pw, md5sum, &MD5out, curlx_uztoui(md5len));
+ PK11_DestroyContext(MD5pw, PR_TRUE);
+}
+
+#endif /* USE_NSS */
diff --git a/libs/libcurl/src/nssg.h b/libs/libcurl/src/nssg.h
new file mode 100644
index 0000000000..cd32706a71
--- /dev/null
+++ b/libs/libcurl/src/nssg.h
@@ -0,0 +1,88 @@
+#ifndef HEADER_CURL_NSSG_H
+#define HEADER_CURL_NSSG_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"
+
+#ifdef USE_NSS
+/*
+ * This header should only be needed to get included by sslgen.c and nss.c
+ */
+
+#include "urldata.h"
+
+CURLcode Curl_nss_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_nss_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+/* close a SSL connection */
+void Curl_nss_close(struct connectdata *conn, int sockindex);
+
+/* tell NSS to close down all open information regarding connections (and
+ thus session ID caching etc) */
+int Curl_nss_close_all(struct SessionHandle *data);
+
+int Curl_nss_init(void);
+void Curl_nss_cleanup(void);
+
+size_t Curl_nss_version(char *buffer, size_t size);
+int Curl_nss_check_cxn(struct connectdata *cxn);
+int Curl_nss_seed(struct SessionHandle *data);
+
+/* initialize NSS library if not already */
+CURLcode Curl_nss_force_init(struct SessionHandle *data);
+
+void Curl_nss_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length);
+
+void Curl_nss_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ 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 NSS */
+#define curlssl_init Curl_nss_init
+#define curlssl_cleanup Curl_nss_cleanup
+#define curlssl_connect Curl_nss_connect
+
+/* NSS has its own session ID cache */
+#define curlssl_session_free(x) Curl_nop_stmt
+#define curlssl_close_all Curl_nss_close_all
+#define curlssl_close Curl_nss_close
+/* NSS has no shutdown function provided and thus always fail */
+#define curlssl_shutdown(x,y) (x=x, y=y, 1)
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_nss_version
+#define curlssl_check_cxn(x) Curl_nss_check_cxn(x)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+#define curlssl_random(x,y,z) Curl_nss_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_nss_md5sum(a,b,c,d)
+
+#endif /* USE_NSS */
+#endif /* HEADER_CURL_NSSG_H */
diff --git a/libs/libcurl/src/nwlib.c b/libs/libcurl/src/nwlib.c
new file mode 100644
index 0000000000..252bf11ec8
--- /dev/null
+++ b/libs/libcurl/src/nwlib.c
@@ -0,0 +1,329 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 NETWARE /* Novell NetWare */
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to register as a real lib. */
+#include <library.h>
+#include <netware.h>
+#include <screen.h>
+#include <nks/thread.h>
+#include <nks/synch.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+typedef struct
+{
+ int _errno;
+ void *twentybytes;
+} libthreaddata_t;
+
+typedef struct
+{
+ int x;
+ int y;
+ int z;
+ void *tenbytes;
+ NXKey_t perthreadkey; /* if -1, no key obtained... */
+ NXMutex_t *lock;
+} libdata_t;
+
+int gLibId = -1;
+void *gLibHandle = (void *) NULL;
+rtag_t gAllocTag = (rtag_t) NULL;
+NXMutex_t *gLibLock = (NXMutex_t *) NULL;
+
+/* internal library function prototypes... */
+int DisposeLibraryData( void * );
+void DisposeThreadData( void * );
+int GetOrSetUpData( int id, libdata_t **data, libthreaddata_t **threaddata );
+
+
+int _NonAppStart( void *NLMHandle,
+ void *errorScreen,
+ const char *cmdLine,
+ const char *loadDirPath,
+ size_t uninitializedDataLength,
+ void *NLMFileHandle,
+ int (*readRoutineP)( int conn,
+ void *fileHandle, size_t offset,
+ size_t nbytes,
+ size_t *bytesRead,
+ void *buffer ),
+ size_t customDataOffset,
+ size_t customDataSize,
+ int messageCount,
+ const char **messages )
+{
+ NX_LOCK_INFO_ALLOC(liblock, "Per-Application Data Lock", 0);
+
+#ifndef __GNUC__
+#pragma unused(cmdLine)
+#pragma unused(loadDirPath)
+#pragma unused(uninitializedDataLength)
+#pragma unused(NLMFileHandle)
+#pragma unused(readRoutineP)
+#pragma unused(customDataOffset)
+#pragma unused(customDataSize)
+#pragma unused(messageCount)
+#pragma unused(messages)
+#endif
+
+ /*
+ * Here we process our command line, post errors (to the error screen),
+ * perform initializations and anything else we need to do before being able
+ * to accept calls into us. If we succeed, we return non-zero and the NetWare
+ * Loader will leave us up, otherwise we fail to load and get dumped.
+ */
+ gAllocTag = AllocateResourceTag(NLMHandle,
+ "<library-name> memory allocations",
+ AllocSignature);
+
+ if(!gAllocTag) {
+ OutputToScreen(errorScreen, "Unable to allocate resource tag for "
+ "library memory allocations.\n");
+ return -1;
+ }
+
+ gLibId = register_library(DisposeLibraryData);
+
+ if(gLibId < -1) {
+ OutputToScreen(errorScreen, "Unable to register library with kernel.\n");
+ return -1;
+ }
+
+ gLibHandle = NLMHandle;
+
+ gLibLock = NXMutexAlloc(0, 0, &liblock);
+
+ if(!gLibLock) {
+ OutputToScreen(errorScreen, "Unable to allocate library data lock.\n");
+ return -1;
+ }
+
+ return 0;
+}
+
+/*
+ * Here we clean up any resources we allocated. Resource tags is a big part
+ * of what we created, but NetWare doesn't ask us to free those.
+ */
+void _NonAppStop( void )
+{
+ (void) unregister_library(gLibId);
+ NXMutexFree(gLibLock);
+}
+
+/*
+ * This function cannot be the first in the file for if the file is linked
+ * first, then the check-unload function's offset will be nlmname.nlm+0
+ * which is how to tell that there isn't one. When the check function is
+ * first in the linked objects, it is ambiguous. For this reason, we will
+ * put it inside this file after the stop function.
+ *
+ * Here we check to see if it's alright to ourselves to be unloaded. If not,
+ * we return a non-zero value. Right now, there isn't any reason not to allow
+ * it.
+ */
+int _NonAppCheckUnload( void )
+{
+ return 0;
+}
+
+int GetOrSetUpData(int id, libdata_t **appData,
+ libthreaddata_t **threadData )
+{
+ int err;
+ libdata_t *app_data;
+ libthreaddata_t *thread_data;
+ NXKey_t key;
+ NX_LOCK_INFO_ALLOC(liblock, "Application Data Lock", 0);
+
+ err = 0;
+ thread_data = (libthreaddata_t *) NULL;
+
+ /*
+ * Attempt to get our data for the application calling us. This is where we
+ * store whatever application-specific information we need to carry in
+ * support of calling applications.
+ */
+ app_data = (libdata_t *) get_app_data(id);
+
+ if(!app_data) {
+ /*
+ * This application hasn't called us before; set up application AND
+ * per-thread data. Of course, just in case a thread from this same
+ * application is calling us simultaneously, we better lock our application
+ * data-creation mutex. We also need to recheck for data after we acquire
+ * the lock because WE might be that other thread that was too late to
+ * create the data and the first thread in will have created it.
+ */
+ NXLock(gLibLock);
+
+ if(!(app_data = (libdata_t *) get_app_data(id))) {
+ app_data = malloc(sizeof(libdata_t));
+
+ if(app_data) {
+ memset(app_data, 0, sizeof(libdata_t));
+
+ app_data->tenbytes = malloc(10);
+ app_data->lock = NXMutexAlloc(0, 0, &liblock);
+
+ if(!app_data->tenbytes || !app_data->lock) {
+ if(app_data->lock)
+ NXMutexFree(app_data->lock);
+
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ if(app_data) {
+ /*
+ * Here we burn in the application data that we were trying to get
+ * by calling get_app_data(). Next time we call the first function,
+ * we'll get this data we're just now setting. We also go on here to
+ * establish the per-thread data for the calling thread, something
+ * we'll have to do on each application thread the first time
+ * it calls us.
+ */
+ err = set_app_data(gLibId, app_data);
+
+ if(err) {
+ free(app_data);
+ app_data = (libdata_t *) NULL;
+ err = ENOMEM;
+ }
+ else {
+ /* create key for thread-specific data... */
+ err = NXKeyCreate(DisposeThreadData, (void *) NULL, &key);
+
+ if(err) /* (no more keys left?) */
+ key = -1;
+
+ app_data->perthreadkey = key;
+ }
+ }
+ }
+ }
+
+ NXUnlock(gLibLock);
+ }
+
+ if(app_data) {
+ key = app_data->perthreadkey;
+
+ if(key != -1 /* couldn't create a key? no thread data */
+ && !(err = NXKeyGetValue(key, (void **) &thread_data))
+ && !thread_data) {
+ /*
+ * Allocate the per-thread data for the calling thread. Regardless of
+ * whether there was already application data or not, this may be the
+ * first call by a new thread. The fact that we allocation 20 bytes on
+ * a pointer is not very important, this just helps to demonstrate that
+ * we can have arbitrarily complex per-thread data.
+ */
+ thread_data = malloc(sizeof(libthreaddata_t));
+
+ if(thread_data) {
+ thread_data->_errno = 0;
+ thread_data->twentybytes = malloc(20);
+
+ if(!thread_data->twentybytes) {
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ err = ENOMEM;
+ }
+
+ if((err = NXKeySetValue(key, thread_data))) {
+ free(thread_data->twentybytes);
+ free(thread_data);
+ thread_data = (libthreaddata_t *) NULL;
+ }
+ }
+ }
+ }
+
+ if(appData)
+ *appData = app_data;
+
+ if(threadData)
+ *threadData = thread_data;
+
+ return err;
+}
+
+int DisposeLibraryData( void *data )
+{
+ if(data) {
+ void *tenbytes = ((libdata_t *) data)->tenbytes;
+
+ if(tenbytes)
+ free(tenbytes);
+
+ free(data);
+ }
+
+ return 0;
+}
+
+void DisposeThreadData( void *data )
+{
+ if(data) {
+ void *twentybytes = ((libthreaddata_t *) data)->twentybytes;
+
+ if(twentybytes)
+ free(twentybytes);
+
+ free(data);
+ }
+}
+
+#else /* __NOVELL_LIBC__ */
+/* For native CLib-based NLM seems we can do a bit more simple. */
+#include <nwthread.h>
+
+int main ( void )
+{
+ /* initialize any globals here... */
+
+ /* do this if any global initializing was done
+ SynchronizeStart();
+ */
+ ExitThread (TSR_THREAD, 0);
+ return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#else /* NETWARE */
+
+#ifdef __POCC__
+# pragma warn(disable:2024) /* Disable warning #2024: Empty input file */
+#endif
+
+#endif /* NETWARE */
diff --git a/libs/libcurl/src/nwos.c b/libs/libcurl/src/nwos.c
new file mode 100644
index 0000000000..23ff2a7172
--- /dev/null
+++ b/libs/libcurl/src/nwos.c
@@ -0,0 +1,88 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 NETWARE /* Novell NetWare */
+
+#ifdef __NOVELL_LIBC__
+/* For native LibC-based NLM we need to do nothing. */
+int netware_init ( void )
+{
+ return 0;
+}
+
+#else /* __NOVELL_LIBC__ */
+
+/* For native CLib-based NLM we need to initialize the LONG namespace. */
+#include <nwnspace.h>
+#include <nwthread.h>
+#include <nwadv.h>
+/* Make the CLIB Ctx stuff link */
+#include <netdb.h>
+NETDB_DEFINE_CONTEXT
+/* Make the CLIB Inet stuff link */
+#include <netinet/in.h>
+#include <arpa/inet.h>
+NETINET_DEFINE_CONTEXT
+
+int netware_init ( void )
+{
+ int rc = 0;
+ unsigned int myHandle = GetNLMHandle();
+ /* import UnAugmentAsterisk dynamically for NW4.x compatibility */
+ void (*pUnAugmentAsterisk)(int) = (void(*)(int))
+ ImportSymbol(myHandle, "UnAugmentAsterisk");
+ /* import UseAccurateCaseForPaths dynamically for NW3.x compatibility */
+ void (*pUseAccurateCaseForPaths)(int) = (void(*)(int))
+ ImportSymbol(myHandle, "UseAccurateCaseForPaths");
+ if(pUnAugmentAsterisk)
+ pUnAugmentAsterisk(1);
+ if(pUseAccurateCaseForPaths)
+ pUseAccurateCaseForPaths(1);
+ UnimportSymbol(myHandle, "UnAugmentAsterisk");
+ UnimportSymbol(myHandle, "UseAccurateCaseForPaths");
+ /* set long name space */
+ if((SetCurrentNameSpace(4) == 255)) {
+ rc = 1;
+ }
+ if((SetTargetNameSpace(4) == 255)) {
+ rc = rc + 2;
+ }
+ return rc;
+}
+
+/* dummy function to satisfy newer prelude */
+int __init_environment ( void )
+{
+ return 0;
+}
+
+/* dummy function to satisfy newer prelude */
+int __deinit_environment ( void )
+{
+ return 0;
+}
+
+#endif /* __NOVELL_LIBC__ */
+
+#endif /* NETWARE */
diff --git a/libs/libcurl/src/openldap.c b/libs/libcurl/src/openldap.c
new file mode 100644
index 0000000000..98793b3067
--- /dev/null
+++ b/libs/libcurl/src/openldap.c
@@ -0,0 +1,639 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
+ * Copyright (C) 2011 - 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"
+
+#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
+
+/*
+ * Notice that USE_OPENLDAP is only a source code selection switch. When
+ * libcurl is built with USE_OPENLDAP defined the libcurl source code that
+ * gets compiled is the code from openldap.c, otherwise the code that gets
+ * compiled is the code from ldap.c.
+ *
+ * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
+ * might be required for compilation and runtime. In order to use ancient
+ * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
+ */
+
+#include <ldap.h>
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "sendf.h"
+#include "sslgen.h"
+#include "transfer.h"
+#include "curl_ldap.h"
+#include "curl_memory.h"
+#include "curl_base64.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "memdebug.h"
+
+#ifndef _LDAP_PVT_H
+extern int ldap_pvt_url_scheme2proto(const char *);
+extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
+ LDAP **ld);
+#endif
+
+static CURLcode ldap_setup(struct connectdata *conn);
+static CURLcode ldap_do(struct connectdata *conn, bool *done);
+static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
+static CURLcode ldap_connect(struct connectdata *conn, bool *done);
+static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
+static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
+
+static Curl_recv ldap_recv;
+
+/*
+ * LDAP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldap = {
+ "LDAP", /* scheme */
+ ldap_setup, /* setup_connection */
+ ldap_do, /* do_it */
+ ldap_done, /* done */
+ ZERO_NULL, /* do_more */
+ ldap_connect, /* connect_it */
+ ldap_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ldap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAP, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * LDAPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_ldaps = {
+ "LDAPS", /* scheme */
+ ldap_setup, /* setup_connection */
+ ldap_do, /* do_it */
+ ldap_done, /* done */
+ ZERO_NULL, /* do_more */
+ ldap_connect, /* connect_it */
+ ldap_connecting, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ldap_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_LDAPS, /* defport */
+ CURLPROTO_LDAP, /* protocol */
+ PROTOPT_SSL /* flags */
+};
+#endif
+
+static const char *url_errs[] = {
+ "success",
+ "out of memory",
+ "bad parameter",
+ "unrecognized scheme",
+ "unbalanced delimiter",
+ "bad URL",
+ "bad host or port",
+ "bad or missing attributes",
+ "bad or missing scope",
+ "bad or missing filter",
+ "bad or missing extensions"
+};
+
+typedef struct ldapconninfo {
+ LDAP *ld;
+ Curl_recv *recv; /* for stacking SSL handler */
+ Curl_send *send;
+ int proto;
+ int msgid;
+ bool ssldone;
+ bool sslinst;
+ bool didbind;
+} ldapconninfo;
+
+typedef struct ldapreqinfo {
+ int msgid;
+ int nument;
+} ldapreqinfo;
+
+static CURLcode ldap_setup(struct connectdata *conn)
+{
+ ldapconninfo *li;
+ LDAPURLDesc *lud;
+ struct SessionHandle *data=conn->data;
+ int rc, proto;
+ CURLcode status;
+
+ rc = ldap_url_parse(data->change.url, &lud);
+ if(rc != LDAP_URL_SUCCESS) {
+ const char *msg = "url parsing problem";
+ status = CURLE_URL_MALFORMAT;
+ if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
+ if(rc == LDAP_URL_ERR_MEM)
+ status = CURLE_OUT_OF_MEMORY;
+ msg = url_errs[rc];
+ }
+ failf(conn->data, "LDAP local: %s", msg);
+ return status;
+ }
+ proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
+ ldap_free_urldesc(lud);
+
+ li = calloc(1, sizeof(ldapconninfo));
+ if(!li)
+ return CURLE_OUT_OF_MEMORY;
+ li->proto = proto;
+ conn->proto.generic = li;
+ conn->bits.close = FALSE;
+ /* TODO:
+ * - provide option to choose SASL Binds instead of Simple
+ */
+ return CURLE_OK;
+}
+
+#ifdef USE_SSL
+static Sockbuf_IO ldapsb_tls;
+#endif
+
+static CURLcode ldap_connect(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct SessionHandle *data=conn->data;
+ int rc, proto = LDAP_VERSION3;
+ char hosturl[1024], *ptr;
+ (void)done;
+
+ strcpy(hosturl, "ldap");
+ ptr = hosturl+4;
+ if(conn->handler->flags & PROTOPT_SSL)
+ *ptr++ = 's';
+ snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
+ conn->host.name, conn->remote_port);
+
+ rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
+ if(rc) {
+ failf(data, "LDAP local: Cannot connect to %s, %s",
+ hosturl, ldap_err2string(rc));
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+
+#ifdef USE_SSL
+ if(conn->handler->flags & PROTOPT_SSL) {
+ CURLcode res;
+ res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
+ if(res)
+ return res;
+ }
+#endif
+
+ return CURLE_OK;
+}
+
+static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct SessionHandle *data=conn->data;
+ LDAPMessage *result = NULL;
+ struct timeval tv = {0,1}, *tvp;
+ int rc, err;
+ char *info = NULL;
+
+#ifdef USE_SSL
+ if(conn->handler->flags & PROTOPT_SSL) {
+ /* Is the SSL handshake complete yet? */
+ if(!li->ssldone) {
+ CURLcode res = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
+ &li->ssldone);
+ if(res || !li->ssldone)
+ return res;
+ }
+ /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
+ if(!li->sslinst) {
+ Sockbuf *sb;
+ ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
+ ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
+ li->sslinst = TRUE;
+ li->recv = conn->recv[FIRSTSOCKET];
+ li->send = conn->send[FIRSTSOCKET];
+ }
+ }
+#endif
+
+ tvp = &tv;
+
+retry:
+ if(!li->didbind) {
+ char *binddn;
+ struct berval passwd;
+
+ if(conn->bits.user_passwd) {
+ binddn = conn->user;
+ passwd.bv_val = conn->passwd;
+ passwd.bv_len = strlen(passwd.bv_val);
+ }
+ else {
+ binddn = NULL;
+ passwd.bv_val = NULL;
+ passwd.bv_len = 0;
+ }
+ rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
+ NULL, NULL, &li->msgid);
+ if(rc)
+ return CURLE_LDAP_CANNOT_BIND;
+ li->didbind = TRUE;
+ if(tvp)
+ return CURLE_OK;
+ }
+
+ rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &result);
+ if(rc < 0) {
+ failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
+ return CURLE_LDAP_CANNOT_BIND;
+ }
+ if(rc == 0) {
+ /* timed out */
+ return CURLE_OK;
+ }
+ rc = ldap_parse_result(li->ld, result, &err, NULL, &info, NULL, NULL, 1);
+ if(rc) {
+ failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
+ return CURLE_LDAP_CANNOT_BIND;
+ }
+ /* Try to fallback to LDAPv2? */
+ if(err == LDAP_PROTOCOL_ERROR) {
+ int proto;
+ ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ if(proto == LDAP_VERSION3) {
+ if(info) {
+ ldap_memfree(info);
+ info = NULL;
+ }
+ proto = LDAP_VERSION2;
+ ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
+ li->didbind = FALSE;
+ goto retry;
+ }
+ }
+
+ if(err) {
+ failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
+ info ? info : "");
+ if(info)
+ ldap_memfree(info);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ if(info)
+ ldap_memfree(info);
+ conn->recv[FIRSTSOCKET] = ldap_recv;
+ *done = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ ldapconninfo *li = conn->proto.generic;
+ (void) dead_connection;
+
+ if(li) {
+ if(li->ld) {
+ ldap_unbind_ext(li->ld, NULL, NULL);
+ li->ld = NULL;
+ }
+ conn->proto.generic = NULL;
+ free(li);
+ }
+ return CURLE_OK;
+}
+
+static CURLcode ldap_do(struct connectdata *conn, bool *done)
+{
+ ldapconninfo *li = conn->proto.generic;
+ ldapreqinfo *lr;
+ CURLcode status = CURLE_OK;
+ int rc = 0;
+ LDAPURLDesc *ludp = NULL;
+ int msgid;
+ struct SessionHandle *data=conn->data;
+
+ conn->bits.close = FALSE;
+
+ infof(data, "LDAP local: %s\n", data->change.url);
+
+ rc = ldap_url_parse(data->change.url, &ludp);
+ if(rc != LDAP_URL_SUCCESS) {
+ const char *msg = "url parsing problem";
+ status = CURLE_URL_MALFORMAT;
+ if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
+ if(rc == LDAP_URL_ERR_MEM)
+ status = CURLE_OUT_OF_MEMORY;
+ msg = url_errs[rc];
+ }
+ failf(conn->data, "LDAP local: %s", msg);
+ return status;
+ }
+
+ rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
+ ludp->lud_filter, ludp->lud_attrs, 0,
+ NULL, NULL, NULL, 0, &msgid);
+ ldap_free_urldesc(ludp);
+ if(rc != LDAP_SUCCESS) {
+ failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
+ return CURLE_LDAP_SEARCH_FAILED;
+ }
+ lr = calloc(1,sizeof(ldapreqinfo));
+ if(!lr)
+ return CURLE_OUT_OF_MEMORY;
+ lr->msgid = msgid;
+ data->req.protop = lr;
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+ *done = TRUE;
+ return CURLE_OK;
+}
+
+static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
+ bool premature)
+{
+ ldapreqinfo *lr = conn->data->req.protop;
+ (void)res;
+ (void)premature;
+
+ if(lr) {
+ /* if there was a search in progress, abandon it */
+ if(lr->msgid) {
+ ldapconninfo *li = conn->proto.generic;
+ ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
+ lr->msgid = 0;
+ }
+ conn->data->req.protop = NULL;
+ free(lr);
+ }
+ return CURLE_OK;
+}
+
+static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
+ size_t len, CURLcode *err)
+{
+ ldapconninfo *li = conn->proto.generic;
+ struct SessionHandle *data=conn->data;
+ ldapreqinfo *lr = data->req.protop;
+ int rc, ret;
+ LDAPMessage *result = NULL;
+ LDAPMessage *ent;
+ BerElement *ber = NULL;
+ struct timeval tv = {0,1};
+ (void)len;
+ (void)buf;
+ (void)sockindex;
+
+ rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &result);
+ if(rc < 0) {
+ failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ *err = CURLE_AGAIN;
+ ret = -1;
+
+ /* timed out */
+ if(result == NULL)
+ return ret;
+
+ for(ent = ldap_first_message(li->ld, result); ent;
+ ent = ldap_next_message(li->ld, ent)) {
+ struct berval bv, *bvals, **bvp = &bvals;
+ int binary = 0, msgtype;
+
+ msgtype = ldap_msgtype(ent);
+ if(msgtype == LDAP_RES_SEARCH_RESULT) {
+ int code;
+ char *info = NULL;
+ rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
+ if(rc) {
+ failf(data, "LDAP local: search ldap_parse_result %s",
+ ldap_err2string(rc));
+ *err = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
+ failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
+ info ? info : "");
+ *err = CURLE_LDAP_SEARCH_FAILED;
+ }
+ else {
+ /* successful */
+ if(code == LDAP_SIZELIMIT_EXCEEDED)
+ infof(data, "There are more than %d entries\n", lr->nument);
+ data->req.size = data->req.bytecount;
+ *err = CURLE_OK;
+ ret = 0;
+ }
+ lr->msgid = 0;
+ ldap_memfree(info);
+ break;
+ }
+ else if(msgtype != LDAP_RES_SEARCH_ENTRY)
+ continue;
+
+ lr->nument++;
+ rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
+ if(rc < 0) {
+ /* TODO: verify that this is really how this return code should be
+ handled */
+ *err = CURLE_RECV_ERROR;
+ return -1;
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val, bv.bv_len);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
+ data->req.bytecount += bv.bv_len + 5;
+
+ for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
+ rc == LDAP_SUCCESS;
+ rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) {
+ int i;
+
+ if(bv.bv_val == NULL) break;
+
+ if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
+ binary = 1;
+ else
+ binary = 0;
+
+ for(i=0; bvals[i].bv_val != NULL; i++) {
+ int binval = 0;
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
+ bv.bv_len);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
+ data->req.bytecount += bv.bv_len + 2;
+
+ if(!binary) {
+ /* check for leading or trailing whitespace */
+ if(ISSPACE(bvals[i].bv_val[0]) ||
+ ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
+ binval = 1;
+ else {
+ /* check for unprintable characters */
+ unsigned int j;
+ for(j=0; j<bvals[i].bv_len; j++)
+ if(!ISPRINT(bvals[i].bv_val[j])) {
+ binval = 1;
+ break;
+ }
+ }
+ }
+ if(binary || binval) {
+ char *val_b64 = NULL;
+ size_t val_b64_sz = 0;
+ /* Binary value, encode to base64. */
+ CURLcode error = Curl_base64_encode(data,
+ bvals[i].bv_val,
+ bvals[i].bv_len,
+ &val_b64,
+ &val_b64_sz);
+ if(error) {
+ ber_memfree(bvals);
+ ber_free(ber, 0);
+ ldap_msgfree(result);
+ *err = error;
+ return -1;
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
+ data->req.bytecount += 2;
+ if(val_b64_sz > 0) {
+ Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz);
+ free(val_b64);
+ data->req.bytecount += val_b64_sz;
+ }
+ }
+ else {
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
+ Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
+ bvals[i].bv_len);
+ data->req.bytecount += bvals[i].bv_len + 1;
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ data->req.bytecount++;
+ }
+ ber_memfree(bvals);
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ data->req.bytecount++;
+ }
+ Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
+ data->req.bytecount++;
+ ber_free(ber, 0);
+ }
+ ldap_msgfree(result);
+ return ret;
+}
+
+#ifdef USE_SSL
+static int
+ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
+{
+ sbiod->sbiod_pvt = arg;
+ return 0;
+}
+
+static int
+ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
+{
+ sbiod->sbiod_pvt = NULL;
+ return 0;
+}
+
+/* We don't need to do anything because libcurl does it already */
+static int
+ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
+{
+ (void)sbiod;
+ return 0;
+}
+
+static int
+ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
+{
+ (void)arg;
+ if(opt == LBER_SB_OPT_DATA_READY) {
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ return Curl_ssl_data_pending(conn, FIRSTSOCKET);
+ }
+ return 0;
+}
+
+static ber_slen_t
+ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ ldapconninfo *li = conn->proto.generic;
+ ber_slen_t ret;
+ CURLcode err = CURLE_RECV_ERROR;
+
+ ret = li->recv(conn, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ return ret;
+}
+
+static ber_slen_t
+ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
+{
+ struct connectdata *conn = sbiod->sbiod_pvt;
+ ldapconninfo *li = conn->proto.generic;
+ ber_slen_t ret;
+ CURLcode err = CURLE_SEND_ERROR;
+
+ ret = li->send(conn, FIRSTSOCKET, buf, len, &err);
+ if(ret < 0 && err == CURLE_AGAIN) {
+ SET_SOCKERRNO(EWOULDBLOCK);
+ }
+ return ret;
+}
+
+static Sockbuf_IO ldapsb_tls =
+{
+ ldapsb_tls_setup,
+ ldapsb_tls_remove,
+ ldapsb_tls_ctrl,
+ ldapsb_tls_read,
+ ldapsb_tls_write,
+ ldapsb_tls_close
+};
+#endif /* USE_SSL */
+
+#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
diff --git a/libs/libcurl/src/parsedate.c b/libs/libcurl/src/parsedate.c
new file mode 100644
index 0000000000..1ddd0080ae
--- /dev/null
+++ b/libs/libcurl/src/parsedate.c
@@ -0,0 +1,580 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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.
+ *
+ ***************************************************************************/
+/*
+ A brief summary of the date string formats this parser groks:
+
+ RFC 2616 3.3.1
+
+ Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
+ Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
+ Sun Nov 6 08:49:37 1994 ; ANSI C's asctime() format
+
+ we support dates without week day name:
+
+ 06 Nov 1994 08:49:37 GMT
+ 06-Nov-94 08:49:37 GMT
+ Nov 6 08:49:37 1994
+
+ without the time zone:
+
+ 06 Nov 1994 08:49:37
+ 06-Nov-94 08:49:37
+
+ weird order:
+
+ 1994 Nov 6 08:49:37 (GNU date fails)
+ GMT 08:49:37 06-Nov-94 Sunday
+ 94 6 Nov 08:49:37 (GNU date fails)
+
+ time left out:
+
+ 1994 Nov 6
+ 06-Nov-94
+ Sun Nov 6 94
+
+ unusual separators:
+
+ 1994.Nov.6
+ Sun/Nov/6/94/GMT
+
+ commonly used time zone names:
+
+ Sun, 06 Nov 1994 08:49:37 CET
+ 06 Nov 1994 08:49:37 EST
+
+ time zones specified using RFC822 style:
+
+ Sun, 12 Sep 2004 15:05:58 -0700
+ Sat, 11 Sep 2004 21:32:11 +0200
+
+ compact numerical date strings:
+
+ 20040912 15:05:58 -0700
+ 20040911 +0200
+
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "rawstr.h"
+#include "warnless.h"
+#include "parsedate.h"
+
+const char * const Curl_wkday[] =
+{"Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"};
+static const char * const weekday[] =
+{ "Monday", "Tuesday", "Wednesday", "Thursday",
+ "Friday", "Saturday", "Sunday" };
+const char * const Curl_month[]=
+{ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+struct tzinfo {
+ char name[5];
+ int offset; /* +/- in minutes */
+};
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK - a fine conversion
+ * PARSEDATE_FAIL - failed to convert
+ * PARSEDATE_LATER - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output);
+
+#define PARSEDATE_OK 0
+#define PARSEDATE_FAIL -1
+#define PARSEDATE_LATER 1
+#define PARSEDATE_SOONER 2
+
+/* Here's a bunch of frequently used time zone names. These were supported
+ by the old getdate parser. */
+#define tDAYZONE -60 /* offset for daylight savings time */
+static const struct tzinfo tz[]= {
+ {"GMT", 0}, /* Greenwich Mean */
+ {"UTC", 0}, /* Universal (Coordinated) */
+ {"WET", 0}, /* Western European */
+ {"BST", 0 tDAYZONE}, /* British Summer */
+ {"WAT", 60}, /* West Africa */
+ {"AST", 240}, /* Atlantic Standard */
+ {"ADT", 240 tDAYZONE}, /* Atlantic Daylight */
+ {"EST", 300}, /* Eastern Standard */
+ {"EDT", 300 tDAYZONE}, /* Eastern Daylight */
+ {"CST", 360}, /* Central Standard */
+ {"CDT", 360 tDAYZONE}, /* Central Daylight */
+ {"MST", 420}, /* Mountain Standard */
+ {"MDT", 420 tDAYZONE}, /* Mountain Daylight */
+ {"PST", 480}, /* Pacific Standard */
+ {"PDT", 480 tDAYZONE}, /* Pacific Daylight */
+ {"YST", 540}, /* Yukon Standard */
+ {"YDT", 540 tDAYZONE}, /* Yukon Daylight */
+ {"HST", 600}, /* Hawaii Standard */
+ {"HDT", 600 tDAYZONE}, /* Hawaii Daylight */
+ {"CAT", 600}, /* Central Alaska */
+ {"AHST", 600}, /* Alaska-Hawaii Standard */
+ {"NT", 660}, /* Nome */
+ {"IDLW", 720}, /* International Date Line West */
+ {"CET", -60}, /* Central European */
+ {"MET", -60}, /* Middle European */
+ {"MEWT", -60}, /* Middle European Winter */
+ {"MEST", -60 tDAYZONE}, /* Middle European Summer */
+ {"CEST", -60 tDAYZONE}, /* Central European Summer */
+ {"MESZ", -60 tDAYZONE}, /* Middle European Summer */
+ {"FWT", -60}, /* French Winter */
+ {"FST", -60 tDAYZONE}, /* French Summer */
+ {"EET", -120}, /* Eastern Europe, USSR Zone 1 */
+ {"WAST", -420}, /* West Australian Standard */
+ {"WADT", -420 tDAYZONE}, /* West Australian Daylight */
+ {"CCT", -480}, /* China Coast, USSR Zone 7 */
+ {"JST", -540}, /* Japan Standard, USSR Zone 8 */
+ {"EAST", -600}, /* Eastern Australian Standard */
+ {"EADT", -600 tDAYZONE}, /* Eastern Australian Daylight */
+ {"GST", -600}, /* Guam Standard, USSR Zone 9 */
+ {"NZT", -720}, /* New Zealand */
+ {"NZST", -720}, /* New Zealand Standard */
+ {"NZDT", -720 tDAYZONE}, /* New Zealand Daylight */
+ {"IDLE", -720}, /* International Date Line East */
+ /* Next up: Military timezone names. RFC822 allowed these, but (as noted in
+ RFC 1123) had their signs wrong. Here we use the correct signs to match
+ actual military usage.
+ */
+ {"A", +1 * 60}, /* Alpha */
+ {"B", +2 * 60}, /* Bravo */
+ {"C", +3 * 60}, /* Charlie */
+ {"D", +4 * 60}, /* Delta */
+ {"E", +5 * 60}, /* Echo */
+ {"F", +6 * 60}, /* Foxtrot */
+ {"G", +7 * 60}, /* Golf */
+ {"H", +8 * 60}, /* Hotel */
+ {"I", +9 * 60}, /* India */
+ /* "J", Juliet is not used as a timezone, to indicate the observer's local
+ time */
+ {"K", +10 * 60}, /* Kilo */
+ {"L", +11 * 60}, /* Lima */
+ {"M", +12 * 60}, /* Mike */
+ {"N", -1 * 60}, /* November */
+ {"O", -2 * 60}, /* Oscar */
+ {"P", -3 * 60}, /* Papa */
+ {"Q", -4 * 60}, /* Quebec */
+ {"R", -5 * 60}, /* Romeo */
+ {"S", -6 * 60}, /* Sierra */
+ {"T", -7 * 60}, /* Tango */
+ {"U", -8 * 60}, /* Uniform */
+ {"V", -9 * 60}, /* Victor */
+ {"W", -10 * 60}, /* Whiskey */
+ {"X", -11 * 60}, /* X-ray */
+ {"Y", -12 * 60}, /* Yankee */
+ {"Z", 0}, /* Zulu, zero meridian, a.k.a. UTC */
+};
+
+/* returns:
+ -1 no day
+ 0 monday - 6 sunday
+*/
+
+static int checkday(const char *check, size_t len)
+{
+ int i;
+ const char * const *what;
+ bool found= FALSE;
+ if(len > 3)
+ what = &weekday[0];
+ else
+ what = &Curl_wkday[0];
+ for(i=0; i<7; i++) {
+ if(Curl_raw_equal(check, what[0])) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?i:-1;
+}
+
+static int checkmonth(const char *check)
+{
+ int i;
+ const char * const *what;
+ bool found= FALSE;
+
+ what = &Curl_month[0];
+ for(i=0; i<12; i++) {
+ if(Curl_raw_equal(check, what[0])) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?i:-1; /* return the offset or -1, no real offset is -1 */
+}
+
+/* return the time zone offset between GMT and the input one, in number
+ of seconds or -1 if the timezone wasn't found/legal */
+
+static int checktz(const char *check)
+{
+ unsigned int i;
+ const struct tzinfo *what;
+ bool found= FALSE;
+
+ what = tz;
+ for(i=0; i< sizeof(tz)/sizeof(tz[0]); i++) {
+ if(Curl_raw_equal(check, what->name)) {
+ found=TRUE;
+ break;
+ }
+ what++;
+ }
+ return found?what->offset*60:-1;
+}
+
+static void skip(const char **date)
+{
+ /* skip everything that aren't letters or digits */
+ while(**date && !ISALNUM(**date))
+ (*date)++;
+}
+
+enum assume {
+ DATE_MDAY,
+ DATE_YEAR,
+ DATE_TIME
+};
+
+/* this is a clone of 'struct tm' but with all fields we don't need or use
+ cut out */
+struct my_tm {
+ int tm_sec;
+ int tm_min;
+ int tm_hour;
+ int tm_mday;
+ int tm_mon;
+ int tm_year;
+};
+
+/* struct tm to time since epoch in GMT time zone.
+ * This is similar to the standard mktime function but for GMT only, and
+ * doesn't suffer from the various bugs and portability problems that
+ * some systems' implementations have.
+ */
+static time_t my_timegm(struct my_tm *tm)
+{
+ static const int month_days_cumulative [12] =
+ { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
+ int month, year, leap_days;
+
+ if(tm->tm_year < 70)
+ /* we don't support years before 1970 as they will cause this function
+ to return a negative value */
+ return -1;
+
+ year = tm->tm_year + 1900;
+ month = tm->tm_mon;
+ if(month < 0) {
+ year += (11 - month) / 12;
+ month = 11 - (11 - month) % 12;
+ }
+ else if(month >= 12) {
+ year -= month / 12;
+ month = month % 12;
+ }
+
+ leap_days = year - (tm->tm_mon <= 1);
+ leap_days = ((leap_days / 4) - (leap_days / 100) + (leap_days / 400)
+ - (1969 / 4) + (1969 / 100) - (1969 / 400));
+
+ return ((((time_t) (year - 1970) * 365
+ + leap_days + month_days_cumulative [month] + tm->tm_mday - 1) * 24
+ + tm->tm_hour) * 60 + tm->tm_min) * 60 + tm->tm_sec;
+}
+
+/*
+ * parsedate()
+ *
+ * Returns:
+ *
+ * PARSEDATE_OK - a fine conversion
+ * PARSEDATE_FAIL - failed to convert
+ * PARSEDATE_LATER - time overflow at the far end of time_t
+ * PARSEDATE_SOONER - time underflow at the low end of time_t
+ */
+
+static int parsedate(const char *date, time_t *output)
+{
+ time_t t = 0;
+ int wdaynum=-1; /* day of the week number, 0-6 (mon-sun) */
+ int monnum=-1; /* month of the year number, 0-11 */
+ int mdaynum=-1; /* day of month, 1 - 31 */
+ int hournum=-1;
+ int minnum=-1;
+ int secnum=-1;
+ int yearnum=-1;
+ int tzoff=-1;
+ struct my_tm tm;
+ enum assume dignext = DATE_MDAY;
+ const char *indate = date; /* save the original pointer */
+ int part = 0; /* max 6 parts */
+
+ while(*date && (part < 6)) {
+ bool found=FALSE;
+
+ skip(&date);
+
+ if(ISALPHA(*date)) {
+ /* a name coming up */
+ char buf[32]="";
+ size_t len;
+ sscanf(date, "%31[ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz]",
+ buf);
+ len = strlen(buf);
+
+ if(wdaynum == -1) {
+ wdaynum = checkday(buf, len);
+ if(wdaynum != -1)
+ found = TRUE;
+ }
+ if(!found && (monnum == -1)) {
+ monnum = checkmonth(buf);
+ if(monnum != -1)
+ found = TRUE;
+ }
+
+ if(!found && (tzoff == -1)) {
+ /* this just must be a time zone string */
+ tzoff = checktz(buf);
+ if(tzoff != -1)
+ found = TRUE;
+ }
+
+ if(!found)
+ return PARSEDATE_FAIL; /* bad string */
+
+ date += len;
+ }
+ else if(ISDIGIT(*date)) {
+ /* a digit */
+ int val;
+ char *end;
+ if((secnum == -1) &&
+ (3 == sscanf(date, "%02d:%02d:%02d", &hournum, &minnum, &secnum))) {
+ /* time stamp! */
+ date += 8;
+ }
+ else if((secnum == -1) &&
+ (2 == sscanf(date, "%02d:%02d", &hournum, &minnum))) {
+ /* time stamp without seconds */
+ date += 5;
+ secnum = 0;
+ }
+ else {
+ long lval;
+ int error;
+ int old_errno;
+
+ old_errno = ERRNO;
+ SET_ERRNO(0);
+ lval = strtol(date, &end, 10);
+ error = ERRNO;
+ if(error != old_errno)
+ SET_ERRNO(old_errno);
+
+ if(error)
+ return PARSEDATE_FAIL;
+
+ if((lval > (long)INT_MAX) || (lval < (long)INT_MIN))
+ return PARSEDATE_FAIL;
+
+ val = curlx_sltosi(lval);
+
+ if((tzoff == -1) &&
+ ((end - date) == 4) &&
+ (val <= 1400) &&
+ (indate< date) &&
+ ((date[-1] == '+' || date[-1] == '-'))) {
+ /* four digits and a value less than or equal to 1400 (to take into
+ account all sorts of funny time zone diffs) and it is preceded
+ with a plus or minus. This is a time zone indication. 1400 is
+ picked since +1300 is frequently used and +1400 is mentioned as
+ an edge number in the document "ISO C 200X Proposal: Timezone
+ Functions" at http://david.tribble.com/text/c0xtimezone.html If
+ anyone has a more authoritative source for the exact maximum time
+ zone offsets, please speak up! */
+ found = TRUE;
+ tzoff = (val/100 * 60 + val%100)*60;
+
+ /* the + and - prefix indicates the local time compared to GMT,
+ this we need ther reversed math to get what we want */
+ tzoff = date[-1]=='+'?-tzoff:tzoff;
+ }
+
+ if(((end - date) == 8) &&
+ (yearnum == -1) &&
+ (monnum == -1) &&
+ (mdaynum == -1)) {
+ /* 8 digits, no year, month or day yet. This is YYYYMMDD */
+ found = TRUE;
+ yearnum = val/10000;
+ monnum = (val%10000)/100-1; /* month is 0 - 11 */
+ mdaynum = val%100;
+ }
+
+ if(!found && (dignext == DATE_MDAY) && (mdaynum == -1)) {
+ if((val > 0) && (val<32)) {
+ mdaynum = val;
+ found = TRUE;
+ }
+ dignext = DATE_YEAR;
+ }
+
+ if(!found && (dignext == DATE_YEAR) && (yearnum == -1)) {
+ yearnum = val;
+ found = TRUE;
+ if(yearnum < 1900) {
+ if(yearnum > 70)
+ yearnum += 1900;
+ else
+ yearnum += 2000;
+ }
+ if(mdaynum == -1)
+ dignext = DATE_MDAY;
+ }
+
+ if(!found)
+ return PARSEDATE_FAIL;
+
+ date = end;
+ }
+ }
+
+ part++;
+ }
+
+ if(-1 == secnum)
+ secnum = minnum = hournum = 0; /* no time, make it zero */
+
+ if((-1 == mdaynum) ||
+ (-1 == monnum) ||
+ (-1 == yearnum))
+ /* lacks vital info, fail */
+ return PARSEDATE_FAIL;
+
+#if SIZEOF_TIME_T < 5
+ /* 32 bit time_t can only hold dates to the beginning of 2038 */
+ if(yearnum > 2037) {
+ *output = 0x7fffffff;
+ return PARSEDATE_LATER;
+ }
+#endif
+
+ if(yearnum < 1970) {
+ *output = 0;
+ return PARSEDATE_SOONER;
+ }
+
+ if((mdaynum > 31) || (monnum > 11) ||
+ (hournum > 23) || (minnum > 59) || (secnum > 60))
+ return PARSEDATE_FAIL; /* clearly an illegal date */
+
+ tm.tm_sec = secnum;
+ tm.tm_min = minnum;
+ tm.tm_hour = hournum;
+ tm.tm_mday = mdaynum;
+ tm.tm_mon = monnum;
+ tm.tm_year = yearnum - 1900;
+
+ /* my_timegm() returns a time_t. time_t is often 32 bits, even on many
+ architectures that feature 64 bit 'long'.
+
+ Some systems have 64 bit time_t and deal with years beyond 2038. However,
+ even on some of the systems with 64 bit time_t mktime() returns -1 for
+ dates beyond 03:14:07 UTC, January 19, 2038. (Such as AIX 5100-06)
+ */
+ t = my_timegm(&tm);
+
+ /* time zone adjust (cast t to int to compare to negative one) */
+ if(-1 != (int)t) {
+
+ /* Add the time zone diff between local time zone and GMT. */
+ long delta = (long)(tzoff!=-1?tzoff:0);
+
+ if((delta>0) && (t + delta < t))
+ return -1; /* time_t overflow */
+
+ t += delta;
+ }
+
+ *output = t;
+
+ return PARSEDATE_OK;
+}
+
+time_t curl_getdate(const char *p, const time_t *now)
+{
+ time_t parsed;
+ int rc = parsedate(p, &parsed);
+ (void)now; /* legacy argument from the past that we ignore */
+
+ switch(rc) {
+ case PARSEDATE_OK:
+ case PARSEDATE_LATER:
+ case PARSEDATE_SOONER:
+ return parsed;
+ }
+ /* everything else is fail */
+ return -1;
+}
+
+/*
+ * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
+ * gmtime_r() or gmtime() functions anywhere else but here.
+ *
+ * To make sure no such function calls slip in, we define them to cause build
+ * errors, which is why we use the name within parentheses in this function.
+ *
+ */
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store)
+{
+ const struct tm *tm;
+#ifdef HAVE_GMTIME_R
+ /* thread-safe version */
+ tm = (struct tm *)gmtime_r(&intime, store);
+#else
+ tm = gmtime(&intime);
+ if(tm)
+ *store = *tm; /* copy the pointed struct to the local copy */
+#endif
+
+ if(!tm)
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ return CURLE_OK;
+}
diff --git a/libs/libcurl/src/parsedate.h b/libs/libcurl/src/parsedate.h
new file mode 100644
index 0000000000..ade0f4f602
--- /dev/null
+++ b/libs/libcurl/src/parsedate.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_PARSEDATE_H
+#define HEADER_CURL_PARSEDATE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+
+extern const char * const Curl_wkday[7];
+extern const char * const Curl_month[12];
+
+CURLcode Curl_gmtime(time_t intime, struct tm *store);
+
+#endif /* HEADER_CURL_PARSEDATE_H */
+
diff --git a/libs/libcurl/src/pingpong.c b/libs/libcurl/src/pingpong.c
new file mode 100644
index 0000000000..3ebeabe537
--- /dev/null
+++ b/libs/libcurl/src/pingpong.c
@@ -0,0 +1,519 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ * 'pingpong' is for generic back-and-forth support functions used by FTP,
+ * IMAP, POP3, SMTP and whatever more that likes them.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include "urldata.h"
+#include "sendf.h"
+#include "select.h"
+#include "progress.h"
+#include "speedcheck.h"
+#include "pingpong.h"
+#include "multiif.h"
+#include "non-ascii.h"
+#include "sslgen.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"
+
+#ifdef USE_PINGPONG
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+ triggered */
+long Curl_pp_state_timeout(struct pingpong *pp)
+{
+ struct connectdata *conn = pp->conn;
+ struct SessionHandle *data=conn->data;
+ long timeout_ms; /* in milliseconds */
+ long timeout2_ms; /* in milliseconds */
+ long response_time= (data->set.server_response_timeout)?
+ data->set.server_response_timeout: pp->response_time;
+
+ /* if CURLOPT_SERVER_RESPONSE_TIMEOUT is set, use that to determine
+ remaining time, or use pp->response because SERVER_RESPONSE_TIMEOUT is
+ supposed to govern the response for any given server response, not for
+ the time from connect to the given server response. */
+
+ /* Without a requested timeout, we only wait 'response_time' seconds for the
+ full response to arrive before we bail out */
+ timeout_ms = response_time -
+ Curl_tvdiff(Curl_tvnow(), pp->response); /* spent time */
+
+ if(data->set.timeout) {
+ /* if timeout is requested, find out how much remaining time we have */
+ timeout2_ms = data->set.timeout - /* timeout time */
+ Curl_tvdiff(Curl_tvnow(), conn->now); /* spent time */
+
+ /* pick the lowest number */
+ timeout_ms = CURLMIN(timeout_ms, timeout2_ms);
+ }
+
+ return timeout_ms;
+}
+
+/*
+ * Curl_pp_statemach()
+ */
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block)
+{
+ struct connectdata *conn = pp->conn;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int rc;
+ long interval_ms;
+ long timeout_ms = Curl_pp_state_timeout(pp);
+ struct SessionHandle *data=conn->data;
+ CURLcode result = CURLE_OK;
+
+ if(timeout_ms <=0 ) {
+ failf(data, "server response timeout");
+ return CURLE_OPERATION_TIMEDOUT; /* already too little time */
+ }
+
+ if(block) {
+ interval_ms = 1000; /* use 1 second timeout intervals */
+ if(timeout_ms < interval_ms)
+ interval_ms = timeout_ms;
+ }
+ else
+ interval_ms = 0; /* immediate */
+
+ if(Curl_pp_moredata(pp))
+ /* We are receiving and there is data in the cache so just read it */
+ rc = 1;
+ else if(!pp->sendleft && Curl_ssl_data_pending(conn, FIRSTSOCKET))
+ /* We are receiving and there is data ready in the SSL library */
+ rc = 1;
+ else
+ rc = Curl_socket_ready(pp->sendleft?CURL_SOCKET_BAD:sock, /* reading */
+ pp->sendleft?sock:CURL_SOCKET_BAD, /* writing */
+ interval_ms);
+
+ if(block) {
+ /* if we didn't wait, we don't have to spend time on this now */
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, Curl_tvnow());
+
+ if(result)
+ return result;
+ }
+
+ if(rc == -1) {
+ failf(data, "select/poll error");
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else if(rc)
+ result = pp->statemach_act(conn);
+
+ return result;
+}
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp)
+{
+ struct connectdata *conn = pp->conn;
+ pp->nread_resp = 0;
+ pp->linestart_resp = conn->data->state.buffer;
+ pp->pending_resp = TRUE;
+ pp->response = Curl_tvnow(); /* start response time-out now! */
+}
+
+
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+ const char *fmt,
+ va_list args)
+{
+ ssize_t bytes_written;
+ size_t write_len;
+ char *fmt_crlf;
+ char *s;
+ CURLcode error;
+ struct connectdata *conn = pp->conn;
+ struct SessionHandle *data = conn->data;
+
+#ifdef HAVE_GSSAPI
+ enum protection_level data_sec = conn->data_prot;
+#endif
+
+ DEBUGASSERT(pp->sendleft == 0);
+ DEBUGASSERT(pp->sendsize == 0);
+ DEBUGASSERT(pp->sendthis == NULL);
+
+ fmt_crlf = aprintf("%s\r\n", fmt); /* append a trailing CRLF */
+ if(!fmt_crlf)
+ return CURLE_OUT_OF_MEMORY;
+
+ s = vaprintf(fmt_crlf, args); /* trailing CRLF appended */
+ free(fmt_crlf);
+ if(!s)
+ return CURLE_OUT_OF_MEMORY;
+
+ bytes_written = 0;
+ write_len = strlen(s);
+
+ Curl_pp_init(pp);
+
+ error = Curl_convert_to_network(data, s, write_len);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(error) {
+ free(s);
+ return error;
+ }
+
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CMD;
+#endif
+ error = Curl_write(conn, conn->sock[FIRSTSOCKET], s, write_len,
+ &bytes_written);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(data_sec > PROT_NONE && data_sec < PROT_LAST);
+ conn->data_prot = data_sec;
+#endif
+
+ if(error) {
+ free(s);
+ return error;
+ }
+
+ if(conn->data->set.verbose)
+ Curl_debug(conn->data, CURLINFO_HEADER_OUT,
+ s, (size_t)bytes_written, conn);
+
+ if(bytes_written != (ssize_t)write_len) {
+ /* the whole chunk was not sent, keep it around and adjust sizes */
+ pp->sendthis = s;
+ pp->sendsize = write_len;
+ pp->sendleft = write_len - bytes_written;
+ }
+ else {
+ free(s);
+ pp->sendthis = NULL;
+ pp->sendleft = pp->sendsize = 0;
+ pp->response = Curl_tvnow();
+ }
+
+ return CURLE_OK;
+}
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+ const char *fmt, ...)
+{
+ CURLcode res;
+ va_list ap;
+ va_start(ap, fmt);
+
+ res = Curl_pp_vsendf(pp, fmt, ap);
+
+ va_end(ap);
+
+ return res;
+}
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *code, /* return the server code if done */
+ size_t *size) /* size of the response */
+{
+ ssize_t perline; /* count bytes per line */
+ bool keepon=TRUE;
+ ssize_t gotbytes;
+ char *ptr;
+ struct connectdata *conn = pp->conn;
+ struct SessionHandle *data = conn->data;
+ char * const buf = data->state.buffer;
+ CURLcode result = CURLE_OK;
+
+ *code = 0; /* 0 for errors or not done */
+ *size = 0;
+
+ ptr=buf + pp->nread_resp;
+
+ /* number of bytes in the current line, so far */
+ perline = (ssize_t)(ptr-pp->linestart_resp);
+
+ keepon=TRUE;
+
+ while((pp->nread_resp<BUFSIZE) && (keepon && !result)) {
+
+ if(pp->cache) {
+ /* we had data in the "cache", copy that instead of doing an actual
+ * read
+ *
+ * pp->cache_size is cast to ssize_t here. This should be safe, because
+ * it would have been populated with something of size int to begin
+ * with, even though its datatype may be larger than an int.
+ */
+ DEBUGASSERT((ptr+pp->cache_size) <= (buf+BUFSIZE+1));
+ memcpy(ptr, pp->cache, pp->cache_size);
+ gotbytes = (ssize_t)pp->cache_size;
+ free(pp->cache); /* free the cache */
+ pp->cache = NULL; /* clear the pointer */
+ pp->cache_size = 0; /* zero the size just in case */
+ }
+ else {
+ int res;
+#ifdef HAVE_GSSAPI
+ enum protection_level prot = conn->data_prot;
+ conn->data_prot = PROT_CLEAR;
+#endif
+ DEBUGASSERT((ptr+BUFSIZE-pp->nread_resp) <= (buf+BUFSIZE+1));
+ res = Curl_read(conn, sockfd, ptr, BUFSIZE-pp->nread_resp,
+ &gotbytes);
+#ifdef HAVE_GSSAPI
+ DEBUGASSERT(prot > PROT_NONE && prot < PROT_LAST);
+ conn->data_prot = prot;
+#endif
+ if(res == CURLE_AGAIN)
+ return CURLE_OK; /* return */
+
+ if((res == CURLE_OK) && (gotbytes > 0))
+ /* convert from the network encoding */
+ res = Curl_convert_from_network(data, ptr, gotbytes);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+
+ if(CURLE_OK != res) {
+ result = (CURLcode)res; /* Set outer result variable to this error. */
+ keepon = FALSE;
+ }
+ }
+
+ if(!keepon)
+ ;
+ else if(gotbytes <= 0) {
+ keepon = FALSE;
+ result = CURLE_RECV_ERROR;
+ failf(data, "response reading failed");
+ }
+ else {
+ /* we got a whole chunk of data, which can be anything from one
+ * byte to a set of lines and possible just a piece of the last
+ * line */
+ ssize_t i;
+ ssize_t clipamount = 0;
+ bool restart = FALSE;
+
+ data->req.headerbytecount += (long)gotbytes;
+
+ pp->nread_resp += gotbytes;
+ for(i = 0; i < gotbytes; ptr++, i++) {
+ perline++;
+ if(*ptr=='\n') {
+ /* a newline is CRLF in pp-talk, so the CR is ignored as
+ the line isn't really terminated until the LF comes */
+
+ /* output debug output if that is requested */
+#ifdef HAVE_GSSAPI
+ if(!conn->sec_complete)
+#endif
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_HEADER_IN,
+ pp->linestart_resp, (size_t)perline, conn);
+
+ /*
+ * We pass all response-lines to the callback function registered
+ * for "headers". The response lines can be seen as a kind of
+ * headers.
+ */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER,
+ pp->linestart_resp, perline);
+ if(result)
+ return result;
+
+ if(pp->endofresp(conn, pp->linestart_resp, perline, code)) {
+ /* This is the end of the last line, copy the last line to the
+ start of the buffer and zero terminate, for old times sake */
+ char *meow;
+ int n;
+ for(meow=pp->linestart_resp, n=0; meow<ptr; meow++, n++)
+ buf[n] = *meow;
+ *meow=0; /* zero terminate */
+ keepon=FALSE;
+ pp->linestart_resp = ptr+1; /* advance pointer */
+ i++; /* skip this before getting out */
+
+ *size = pp->nread_resp; /* size of the response */
+ pp->nread_resp = 0; /* restart */
+ break;
+ }
+ perline=0; /* line starts over here */
+ pp->linestart_resp = ptr+1;
+ }
+ }
+
+ if(!keepon && (i != gotbytes)) {
+ /* We found the end of the response lines, but we didn't parse the
+ full chunk of data we have read from the server. We therefore need
+ to store the rest of the data to be checked on the next invoke as
+ it may actually contain another end of response already! */
+ clipamount = gotbytes - i;
+ restart = TRUE;
+ DEBUGF(infof(data, "Curl_pp_readresp_ %d bytes of trailing "
+ "server response left\n",
+ (int)clipamount));
+ }
+ else if(keepon) {
+
+ if((perline == gotbytes) && (gotbytes > BUFSIZE/2)) {
+ /* We got an excessive line without newlines and we need to deal
+ with it. We keep the first bytes of the line then we throw
+ away the rest. */
+ infof(data, "Excessive server response line length received, "
+ "%zd bytes. Stripping\n", gotbytes);
+ restart = TRUE;
+
+ /* we keep 40 bytes since all our pingpong protocols are only
+ interested in the first piece */
+ clipamount = 40;
+ }
+ else if(pp->nread_resp > BUFSIZE/2) {
+ /* We got a large chunk of data and there's potentially still
+ trailing data to take care of, so we put any such part in the
+ "cache", clear the buffer to make space and restart. */
+ clipamount = perline;
+ restart = TRUE;
+ }
+ }
+ else if(i == gotbytes)
+ restart = TRUE;
+
+ if(clipamount) {
+ pp->cache_size = clipamount;
+ pp->cache = malloc(pp->cache_size);
+ if(pp->cache)
+ memcpy(pp->cache, pp->linestart_resp, pp->cache_size);
+ else
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(restart) {
+ /* now reset a few variables to start over nicely from the start of
+ the big buffer */
+ pp->nread_resp = 0; /* start over from scratch in the buffer */
+ ptr = pp->linestart_resp = buf;
+ perline = 0;
+ }
+
+ } /* there was data */
+
+ } /* while there's buffer left and loop is requested */
+
+ pp->pending_resp = FALSE;
+
+ return result;
+}
+
+int Curl_pp_getsock(struct pingpong *pp,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ struct connectdata *conn = pp->conn;
+
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ if(pp->sendleft) {
+ /* write mode */
+ return GETSOCK_WRITESOCK(0);
+ }
+
+ /* read mode */
+ return GETSOCK_READSOCK(0);
+}
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp)
+{
+ /* we have a piece of a command still left to send */
+ struct connectdata *conn = pp->conn;
+ ssize_t written;
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+
+ result = Curl_write(conn, sock, pp->sendthis + pp->sendsize -
+ pp->sendleft, pp->sendleft, &written);
+ if(result)
+ return result;
+
+ if(written != (ssize_t)pp->sendleft) {
+ /* only a fraction was sent */
+ pp->sendleft -= written;
+ }
+ else {
+ free(pp->sendthis);
+ pp->sendthis=NULL;
+ pp->sendleft = pp->sendsize = 0;
+ pp->response = Curl_tvnow();
+ }
+ return CURLE_OK;
+}
+
+CURLcode Curl_pp_disconnect(struct pingpong *pp)
+{
+ if(pp->cache) {
+ free(pp->cache);
+ pp->cache = NULL;
+ }
+ return CURLE_OK;
+}
+
+bool Curl_pp_moredata(struct pingpong *pp)
+{
+ return (!pp->sendleft && pp->cache && pp->nread_resp < pp->cache_size) ?
+ TRUE : FALSE;
+}
+
+#endif
diff --git a/libs/libcurl/src/pingpong.h b/libs/libcurl/src/pingpong.h
new file mode 100644
index 0000000000..b925ab98e1
--- /dev/null
+++ b/libs/libcurl/src/pingpong.h
@@ -0,0 +1,150 @@
+#ifndef HEADER_CURL_PINGPONG_H
+#define HEADER_CURL_PINGPONG_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"
+
+#if !defined(CURL_DISABLE_IMAP) || !defined(CURL_DISABLE_FTP) || \
+ !defined(CURL_DISABLE_POP3) || !defined(CURL_DISABLE_SMTP)
+#define USE_PINGPONG
+#endif
+
+/* forward-declaration, this is defined in urldata.h */
+struct connectdata;
+
+typedef enum {
+ FTPTRANSFER_BODY, /* yes do transfer a body */
+ FTPTRANSFER_INFO, /* do still go through to get info/headers */
+ FTPTRANSFER_NONE, /* don't get anything and don't get info */
+ FTPTRANSFER_LAST /* end of list marker, never used */
+} curl_pp_transfer;
+
+/*
+ * 'pingpong' is the generic struct used for protocols doing server<->client
+ * conversations in a back-and-forth style such as FTP, IMAP, POP3, SMTP etc.
+ *
+ * It holds response cache and non-blocking sending data.
+ */
+struct pingpong {
+ char *cache; /* data cache between getresponse()-calls */
+ size_t cache_size; /* size of cache in bytes */
+ size_t nread_resp; /* number of bytes currently read of a server response */
+ char *linestart_resp; /* line start pointer for the server response
+ reader function */
+ bool pending_resp; /* set TRUE when a server response is pending or in
+ progress, and is cleared once the last response is
+ read */
+ char *sendthis; /* allocated pointer to a buffer that is to be sent to the
+ server */
+ size_t sendleft; /* number of bytes left to send from the sendthis buffer */
+ size_t sendsize; /* total size of the sendthis buffer */
+ struct timeval response; /* set to Curl_tvnow() when a command has been sent
+ off, used to time-out response reading */
+ long response_time; /* When no timeout is given, this is the amount of
+ milliseconds we await for a server response. */
+
+ struct connectdata *conn; /* points to the connectdata struct that this
+ belongs to */
+
+ /* Function pointers the protocols MUST implement and provide for the
+ pingpong layer to function */
+
+ CURLcode (*statemach_act)(struct connectdata *conn);
+
+ bool (*endofresp)(struct connectdata *conn, char *ptr, size_t len,
+ int *code);
+};
+
+/*
+ * Curl_pp_statemach()
+ *
+ * called repeatedly until done. Set 'wait' to make it wait a while on the
+ * socket if there's no traffic.
+ */
+CURLcode Curl_pp_statemach(struct pingpong *pp, bool block);
+
+/* initialize stuff to prepare for reading a fresh new response */
+void Curl_pp_init(struct pingpong *pp);
+
+/* Returns timeout in ms. 0 or negative number means the timeout has already
+ triggered */
+long Curl_pp_state_timeout(struct pingpong *pp);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_sendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_sendf(struct pingpong *pp,
+ const char *fmt, ...);
+
+/***********************************************************************
+ *
+ * Curl_pp_vsendf()
+ *
+ * Send the formated string as a command to a pingpong server. Note that
+ * the string should not have any CRLF appended, as this function will
+ * append the necessary things itself.
+ *
+ * made to never block
+ */
+CURLcode Curl_pp_vsendf(struct pingpong *pp,
+ const char *fmt,
+ va_list args);
+
+/*
+ * Curl_pp_readresp()
+ *
+ * Reads a piece of a server response.
+ */
+CURLcode Curl_pp_readresp(curl_socket_t sockfd,
+ struct pingpong *pp,
+ int *code, /* return the server code if done */
+ size_t *size); /* size of the response */
+
+
+CURLcode Curl_pp_flushsend(struct pingpong *pp);
+
+/* call this when a pingpong connection is disconnected */
+CURLcode Curl_pp_disconnect(struct pingpong *pp);
+
+int Curl_pp_getsock(struct pingpong *pp, curl_socket_t *socks,
+ int numsocks);
+
+
+/***********************************************************************
+ *
+ * Curl_pp_moredata()
+ *
+ * Returns whether there are still more data in the cache and so a call
+ * to Curl_pp_readresp() will not block.
+ */
+bool Curl_pp_moredata(struct pingpong *pp);
+
+#endif /* HEADER_CURL_PINGPONG_H */
diff --git a/libs/libcurl/src/pipeline.c b/libs/libcurl/src/pipeline.c
new file mode 100644
index 0000000000..418058afa0
--- /dev/null
+++ b/libs/libcurl/src/pipeline.c
@@ -0,0 +1,333 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
+ * 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.
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "url.h"
+#include "progress.h"
+#include "multiif.h"
+#include "pipeline.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "bundles.h"
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+struct site_blacklist_entry {
+ char *hostname;
+ unsigned short port;
+};
+
+static void site_blacklist_llist_dtor(void *user, void *element)
+{
+ struct site_blacklist_entry *entry = element;
+ (void)user;
+
+ Curl_safefree(entry->hostname);
+ Curl_safefree(entry);
+}
+
+static void server_blacklist_llist_dtor(void *user, void *element)
+{
+ char *server_name = element;
+ (void)user;
+
+ Curl_safefree(server_name);
+}
+
+bool Curl_pipeline_penalized(struct SessionHandle *data,
+ struct connectdata *conn)
+{
+ if(data) {
+ bool penalized = FALSE;
+ curl_off_t penalty_size =
+ Curl_multi_content_length_penalty_size(data->multi);
+ curl_off_t chunk_penalty_size =
+ Curl_multi_chunk_length_penalty_size(data->multi);
+ curl_off_t recv_size = -2; /* Make it easy to spot in the log */
+
+ /* Find the head of the recv pipe, if any */
+ if(conn->recv_pipe && conn->recv_pipe->head) {
+ struct SessionHandle *recv_handle = conn->recv_pipe->head->ptr;
+
+ recv_size = recv_handle->req.size;
+
+ if(penalty_size > 0 && recv_size > penalty_size)
+ penalized = TRUE;
+ }
+
+ if(chunk_penalty_size > 0 &&
+ (curl_off_t)conn->chunk.datasize > chunk_penalty_size)
+ penalized = TRUE;
+
+ infof(data, "Conn: %ld (%p) Receive pipe weight: (%" FORMAT_OFF_T
+ "/%zu), penalized: %s\n",
+ conn->connection_id, (void *)conn, recv_size,
+ conn->chunk.datasize, penalized?"TRUE":"FALSE");
+ return penalized;
+ }
+ return FALSE;
+}
+
+CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *sendhead = conn->send_pipe->head;
+ struct curl_llist *pipeline;
+ CURLcode rc;
+
+ pipeline = conn->send_pipe;
+
+ infof(conn->data, "Adding handle: conn: %p\n", (void *)conn);
+ infof(conn->data, "Adding handle: send: %d\n", conn->send_pipe->size);
+ infof(conn->data, "Adding handle: recv: %d\n", conn->recv_pipe->size);
+ rc = Curl_addHandleToPipeline(handle, pipeline);
+
+ if(pipeline == conn->send_pipe && sendhead != conn->send_pipe->head) {
+ /* this is a new one as head, expire it */
+ conn->writechannel_inuse = FALSE; /* not in use yet */
+#ifdef DEBUGBUILD
+ infof(conn->data, "%p is at send pipe head!\n",
+ (void *)conn->send_pipe->head->ptr);
+#endif
+ Curl_expire(conn->send_pipe->head->ptr, 1);
+ }
+
+ print_pipeline(conn);
+
+ return rc;
+}
+
+/* Move this transfer from the sending list to the receiving list.
+
+ Pay special attention to the new sending list "leader" as it needs to get
+ checked to update what sockets it acts on.
+
+*/
+void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
+ struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+
+ curr = conn->send_pipe->head;
+ while(curr) {
+ if(curr->ptr == handle) {
+ Curl_llist_move(conn->send_pipe, curr,
+ conn->recv_pipe, conn->recv_pipe->tail);
+
+ if(conn->send_pipe->head) {
+ /* Since there's a new easy handle at the start of the send pipeline,
+ set its timeout value to 1ms to make it trigger instantly */
+ conn->writechannel_inuse = FALSE; /* not used now */
+#ifdef DEBUGBUILD
+ infof(conn->data, "%p is at send pipe head B!\n",
+ (void *)conn->send_pipe->head->ptr);
+#endif
+ Curl_expire(conn->send_pipe->head->ptr, 1);
+ }
+
+ /* The receiver's list is not really interesting here since either this
+ handle is now first in the list and we'll deal with it soon, or
+ another handle is already first and thus is already taken care of */
+
+ break; /* we're done! */
+ }
+ curr = curr->next;
+ }
+}
+
+bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
+ struct connectdata *conn)
+{
+ if(handle->multi) {
+ struct curl_llist *blacklist =
+ Curl_multi_pipelining_site_bl(handle->multi);
+
+ if(blacklist) {
+ struct curl_llist_element *curr;
+
+ curr = blacklist->head;
+ while(curr) {
+ struct site_blacklist_entry *site;
+
+ site = curr->ptr;
+ if(Curl_raw_equal(site->hostname, conn->host.name) &&
+ site->port == conn->remote_port) {
+ infof(handle, "Site %s:%d is pipeline blacklisted\n",
+ conn->host.name, conn->remote_port);
+ return TRUE;
+ }
+ curr = curr->next;
+ }
+ }
+ }
+ return FALSE;
+}
+
+CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
+ struct curl_llist **list_ptr)
+{
+ struct curl_llist *old_list = *list_ptr;
+ struct curl_llist *new_list = NULL;
+
+ if(sites) {
+ new_list = Curl_llist_alloc((curl_llist_dtor) site_blacklist_llist_dtor);
+ if(!new_list)
+ return CURLM_OUT_OF_MEMORY;
+
+ /* Parse the URLs and populate the list */
+ while(*sites) {
+ char *hostname;
+ char *port;
+ struct site_blacklist_entry *entry;
+
+ entry = malloc(sizeof(struct site_blacklist_entry));
+
+ hostname = strdup(*sites);
+ if(!hostname)
+ return CURLM_OUT_OF_MEMORY;
+
+ port = strchr(hostname, ':');
+ if(port) {
+ *port = '\0';
+ port++;
+ entry->port = (unsigned short)strtol(port, NULL, 10);
+ }
+ else {
+ /* Default port number for HTTP */
+ entry->port = 80;
+ }
+
+ entry->hostname = hostname;
+
+ if(!Curl_llist_insert_next(new_list, new_list->tail, entry))
+ return CURLM_OUT_OF_MEMORY;
+
+ sites++;
+ }
+ }
+
+ /* Free the old list */
+ if(old_list) {
+ Curl_llist_destroy(old_list, NULL);
+ }
+
+ /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
+ *list_ptr = new_list;
+
+ return CURLM_OK;
+}
+
+bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
+ char *server_name)
+{
+ if(handle->multi) {
+ struct curl_llist *blacklist =
+ Curl_multi_pipelining_server_bl(handle->multi);
+
+ if(blacklist) {
+ struct curl_llist_element *curr;
+
+ curr = blacklist->head;
+ while(curr) {
+ char *bl_server_name;
+
+ bl_server_name = curr->ptr;
+ if(Curl_raw_nequal(bl_server_name, server_name,
+ strlen(bl_server_name))) {
+ infof(handle, "Server %s is blacklisted\n", server_name);
+ return TRUE;
+ }
+ curr = curr->next;
+ }
+ }
+
+ infof(handle, "Server %s is not blacklisted\n", server_name);
+ }
+ return FALSE;
+}
+
+CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
+ struct curl_llist **list_ptr)
+{
+ struct curl_llist *old_list = *list_ptr;
+ struct curl_llist *new_list = NULL;
+
+ if(servers) {
+ new_list = Curl_llist_alloc((curl_llist_dtor) server_blacklist_llist_dtor);
+ if(!new_list)
+ return CURLM_OUT_OF_MEMORY;
+
+ /* Parse the URLs and populate the list */
+ while(*servers) {
+ char *server_name;
+
+ server_name = strdup(*servers);
+ if(!server_name)
+ return CURLM_OUT_OF_MEMORY;
+
+ if(!Curl_llist_insert_next(new_list, new_list->tail, server_name))
+ return CURLM_OUT_OF_MEMORY;
+
+ servers++;
+ }
+ }
+
+ /* Free the old list */
+ if(old_list) {
+ Curl_llist_destroy(old_list, NULL);
+ }
+
+ /* This might be NULL if sites == NULL, i.e the blacklist is cleared */
+ *list_ptr = new_list;
+
+ return CURLM_OK;
+}
+
+
+void print_pipeline(struct connectdata *conn)
+{
+ struct curl_llist_element *curr;
+ struct connectbundle *cb_ptr;
+ struct SessionHandle *data = conn->data;
+
+ cb_ptr = conn->bundle;
+
+ if(cb_ptr) {
+ curr = cb_ptr->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+ infof(data, "- Conn %ld (%p) send_pipe: %zu, recv_pipe: %zu\n",
+ conn->connection_id,
+ (void *)conn,
+ conn->send_pipe->size,
+ conn->recv_pipe->size);
+ curr = curr->next;
+ }
+ }
+}
diff --git a/libs/libcurl/src/pipeline.h b/libs/libcurl/src/pipeline.h
new file mode 100644
index 0000000000..1df9589535
--- /dev/null
+++ b/libs/libcurl/src/pipeline.h
@@ -0,0 +1,46 @@
+#ifndef HEADER_CURL_PIPELINE_H
+#define HEADER_CURL_PIPELINE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2013, Linus Nielsen Feltzing, <linus@haxx.se>
+ *
+ * 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.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_add_handle_to_pipeline(struct SessionHandle *handle,
+ struct connectdata *conn);
+void Curl_move_handle_from_send_to_recv_pipe(struct SessionHandle *handle,
+ struct connectdata *conn);
+bool Curl_pipeline_penalized(struct SessionHandle *data,
+ struct connectdata *conn);
+
+bool Curl_pipeline_site_blacklisted(struct SessionHandle *handle,
+ struct connectdata *conn);
+
+CURLMcode Curl_pipeline_set_site_blacklist(char **sites,
+ struct curl_llist **list_ptr);
+
+bool Curl_pipeline_server_blacklisted(struct SessionHandle *handle,
+ char *server_name);
+
+CURLMcode Curl_pipeline_set_server_blacklist(char **servers,
+ struct curl_llist **list_ptr);
+
+void print_pipeline(struct connectdata *conn);
+
+#endif /* HEADER_CURL_PIPELINE_H */
diff --git a/libs/libcurl/src/polarssl.c b/libs/libcurl/src/polarssl.c
new file mode 100644
index 0000000000..808f54c243
--- /dev/null
+++ b/libs/libcurl/src/polarssl.c
@@ -0,0 +1,706 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ * Copyright (C) 2012 - 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all PolarSSL-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ *
+ */
+
+#include "curl_setup.h"
+
+#ifdef USE_POLARSSL
+
+#include <polarssl/net.h>
+#include <polarssl/ssl.h>
+#include <polarssl/certs.h>
+#include <polarssl/x509.h>
+#include <polarssl/version.h>
+
+#if POLARSSL_VERSION_NUMBER >= 0x01000000
+#include <polarssl/error.h>
+#endif /* POLARSSL_VERSION_NUMBER >= 0x01000000 */
+
+#if POLARSSL_VERSION_NUMBER>0x01010000
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#else
+#include <polarssl/havege.h>
+#endif /* POLARSSL_VERSION_NUMBER>0x01010000 */
+
+
+#if POLARSSL_VERSION_NUMBER<0x01000000
+/*
+ Earlier versions of polarssl had no WANT_READ or WANT_WRITE, only TRY_AGAIN
+*/
+#define POLARSSL_ERR_NET_WANT_READ POLARSSL_ERR_NET_TRY_AGAIN
+#define POLARSSL_ERR_NET_WANT_WRITE POLARSSL_ERR_NET_TRY_AGAIN
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "polarssl.h"
+#include "sslgen.h"
+#include "parsedate.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "rawstr.h"
+#include "polarssl_threadlock.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"
+
+/* apply threading? */
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+#define THREADING_SUPPORT
+#endif
+
+#if defined(THREADING_SUPPORT) && POLARSSL_VERSION_NUMBER>0x01010000
+static entropy_context entropy;
+
+static int entropy_init_initialized = 0;
+
+/* start of entropy_init_mutex() */
+static void entropy_init_mutex(entropy_context *ctx)
+{
+ /* lock 0 = entropy_init_mutex() */
+ polarsslthreadlock_lock_function(0);
+ if(entropy_init_initialized == 0) {
+ entropy_init(ctx);
+ entropy_init_initialized = 1;
+ }
+ polarsslthreadlock_unlock_function(0);
+}
+/* end of entropy_init_mutex() */
+
+/* start of entropy_func_mutex() */
+static int entropy_func_mutex(void *data, unsigned char *output, size_t len)
+{
+ int ret;
+ /* lock 1 = entropy_func_mutex() */
+ polarsslthreadlock_lock_function(1);
+ ret = entropy_func(data, output, len);
+ polarsslthreadlock_unlock_function(1);
+
+ return ret;
+}
+/* end of entropy_func_mutex() */
+
+#endif /* THREADING_SUPPORT && POLARSSL_VERSION_NUMBER>0x01010000 */
+
+/* Define this to enable lots of debugging for PolarSSL */
+#undef POLARSSL_DEBUG
+
+#ifdef POLARSSL_DEBUG
+static void polarssl_debug(void *context, int level, char *line)
+{
+ struct SessionHandle *data = NULL;
+
+ if(!context)
+ return;
+
+ data = (struct SessionHandle *)context;
+
+ infof(data, "%s\n", line);
+}
+#else
+#endif
+
+static Curl_recv polarssl_recv;
+static Curl_send polarssl_send;
+
+
+static CURLcode
+polarssl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+
+ bool sni = TRUE; /* default is SNI enabled */
+ int ret = -1;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+ void *old_session = NULL;
+ size_t old_session_size = 0;
+
+ char errorbuf[128];
+ memset(errorbuf, 0, sizeof(errorbuf));
+
+
+ /* PolarSSL only supports SSLv3 and TLSv1 */
+ if(data->set.ssl.version == CURL_SSLVERSION_SSLv2) {
+ failf(data, "PolarSSL does not support SSLv2");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(data->set.ssl.version == CURL_SSLVERSION_SSLv3)
+ sni = FALSE; /* SSLv3 has no SNI */
+
+#if POLARSSL_VERSION_NUMBER<0x01010000
+ havege_init(&connssl->hs);
+#else
+#ifdef THREADING_SUPPORT
+ entropy_init_mutex(&entropy);
+
+ if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func_mutex, &entropy,
+ connssl->ssn.id, connssl->ssn.length)) != 0) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#else
+ entropy_init(&connssl->entropy);
+
+ if((ret = ctr_drbg_init(&connssl->ctr_drbg, entropy_func, &connssl->entropy,
+ connssl->ssn.id, connssl->ssn.length)) != 0) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Failed - PolarSSL: ctr_drbg_init returned (-0x%04X) %s\n",
+ -ret, errorbuf);
+ }
+#endif /* THREADING_SUPPORT */
+#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+
+ /* Load the trusted CA */
+ memset(&connssl->cacert, 0, sizeof(x509_cert));
+
+ if(data->set.str[STRING_SSL_CAFILE]) {
+ ret = x509parse_crtfile(&connssl->cacert,
+ data->set.str[STRING_SSL_CAFILE]);
+
+ if(ret<0) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Error reading ca cert file %s - PolarSSL: (-0x%04X) %s",
+ data->set.str[STRING_SSL_CAFILE], -ret, errorbuf);
+
+ if(data->set.ssl.verifypeer)
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ }
+
+ /* Load the client certificate */
+ memset(&connssl->clicert, 0, sizeof(x509_cert));
+
+ if(data->set.str[STRING_CERT]) {
+ ret = x509parse_crtfile(&connssl->clicert,
+ data->set.str[STRING_CERT]);
+
+ if(ret) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Error reading client cert file %s - PolarSSL: (-0x%04X) %s",
+ data->set.str[STRING_CERT], -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the client private key */
+ if(data->set.str[STRING_KEY]) {
+ ret = x509parse_keyfile(&connssl->rsa,
+ data->set.str[STRING_KEY],
+ data->set.str[STRING_KEY_PASSWD]);
+
+ if(ret) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Error reading private key %s - PolarSSL: (-0x%04X) %s",
+ data->set.str[STRING_KEY], -ret, errorbuf);
+
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ /* Load the CRL */
+ memset(&connssl->crl, 0, sizeof(x509_crl));
+
+ if(data->set.str[STRING_SSL_CRLFILE]) {
+ ret = x509parse_crlfile(&connssl->crl,
+ data->set.str[STRING_SSL_CRLFILE]);
+
+ if(ret) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "Error reading CRL file %s - PolarSSL: (-0x%04X) %s",
+ data->set.str[STRING_SSL_CRLFILE], -ret, errorbuf);
+
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ }
+
+ infof(data, "PolarSSL: Connecting to %s:%d\n",
+ conn->host.name, conn->remote_port);
+
+ if(ssl_init(&connssl->ssl)) {
+ failf(data, "PolarSSL: ssl_init failed");
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ ssl_set_endpoint(&connssl->ssl, SSL_IS_CLIENT);
+ ssl_set_authmode(&connssl->ssl, SSL_VERIFY_OPTIONAL);
+
+#if POLARSSL_VERSION_NUMBER<0x01010000
+ ssl_set_rng(&connssl->ssl, havege_rand,
+ &connssl->hs);
+#else
+ ssl_set_rng(&connssl->ssl, ctr_drbg_random,
+ &connssl->ctr_drbg);
+#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+ ssl_set_bio(&connssl->ssl,
+ net_recv, &conn->sock[sockindex],
+ net_send, &conn->sock[sockindex]);
+
+
+#if POLARSSL_VERSION_NUMBER<0x01000000
+ ssl_set_ciphers(&connssl->ssl, ssl_default_ciphers);
+#else
+ ssl_set_ciphersuites(&connssl->ssl, ssl_default_ciphersuites);
+#endif
+ if(!Curl_ssl_getsessionid(conn, &old_session, &old_session_size)) {
+ memcpy(&connssl->ssn, old_session, old_session_size);
+ infof(data, "PolarSSL re-using session\n");
+ }
+
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+ 1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
+ ssl_set_session(&connssl->ssl, 1, 600,
+ &connssl->ssn);
+#else
+ ssl_set_session(&connssl->ssl,
+ &connssl->ssn);
+#endif
+
+ ssl_set_ca_chain(&connssl->ssl,
+ &connssl->cacert,
+ &connssl->crl,
+ conn->host.name);
+
+ ssl_set_own_cert(&connssl->ssl,
+ &connssl->clicert, &connssl->rsa);
+
+ if(!Curl_inet_pton(AF_INET, conn->host.name, &addr) &&
+#ifdef ENABLE_IPV6
+ !Curl_inet_pton(AF_INET6, conn->host.name, &addr) &&
+#endif
+ sni && ssl_set_hostname(&connssl->ssl, conn->host.name)) {
+ infof(data, "WARNING: failed to configure "
+ "server name indication (SNI) TLS extension\n");
+ }
+
+#ifdef POLARSSL_DEBUG
+ ssl_set_dbg(&connssl->ssl, polarssl_debug, data);
+#endif
+
+ connssl->connecting_state = ssl_connect_2;
+
+ return CURLE_OK;
+}
+
+static CURLcode
+polarssl_connect_step2(struct connectdata *conn,
+ int sockindex)
+{
+ int ret;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data* connssl = &conn->ssl[sockindex];
+ char buffer[1024];
+
+ char errorbuf[128];
+ memset(errorbuf, 0, sizeof(errorbuf));
+
+ conn->recv[sockindex] = polarssl_recv;
+ conn->send[sockindex] = polarssl_send;
+
+ for(;;) {
+ if(!(ret = ssl_handshake(&connssl->ssl)))
+ break;
+ else if(ret != POLARSSL_ERR_NET_WANT_READ &&
+ ret != POLARSSL_ERR_NET_WANT_WRITE) {
+#ifdef POLARSSL_ERROR_C
+ error_strerror(ret, errorbuf, sizeof(errorbuf));
+#endif /* POLARSSL_ERROR_C */
+ failf(data, "ssl_handshake returned - PolarSSL: (-0x%04X) %s",
+ -ret, errorbuf);
+
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ if(ret == POLARSSL_ERR_NET_WANT_READ) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ if(ret == POLARSSL_ERR_NET_WANT_WRITE) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ failf(data, "SSL_connect failed with error %d.", ret);
+ return CURLE_SSL_CONNECT_ERROR;
+
+ }
+ }
+
+ infof(data, "PolarSSL: Handshake complete, cipher is %s\n",
+#if POLARSSL_VERSION_NUMBER<0x01000000
+ ssl_get_cipher(&conn->ssl[sockindex].ssl)
+#elif POLARSSL_VERSION_NUMBER >= 0x01010000
+ ssl_get_ciphersuite(&conn->ssl[sockindex].ssl)
+#else
+ ssl_get_ciphersuite_name(&conn->ssl[sockindex].ssl)
+#endif
+ );
+
+ ret = ssl_get_verify_result(&conn->ssl[sockindex].ssl);
+
+ if(ret && data->set.ssl.verifypeer) {
+ if(ret & BADCERT_EXPIRED)
+ failf(data, "Cert verify failed: BADCERT_EXPIRED");
+
+ if(ret & BADCERT_REVOKED) {
+ failf(data, "Cert verify failed: BADCERT_REVOKED");
+ return CURLE_SSL_CACERT;
+ }
+
+ if(ret & BADCERT_CN_MISMATCH)
+ failf(data, "Cert verify failed: BADCERT_CN_MISMATCH");
+
+ if(ret & BADCERT_NOT_TRUSTED)
+ failf(data, "Cert verify failed: BADCERT_NOT_TRUSTED");
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+ 1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
+ if(conn->ssl[sockindex].ssl.peer_cert) {
+#else
+ if(ssl_get_peer_cert(&(connssl->ssl))) {
+#endif
+ /* If the session was resumed, there will be no peer certs */
+ memset(buffer, 0, sizeof(buffer));
+
+/* PolarSSL SVN revision r1316 to r1317, matching <1.2.0 is to cover Ubuntu's
+ 1.1.4 version and the like */
+#if POLARSSL_VERSION_NUMBER<0x01020000
+ if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ",
+ conn->ssl[sockindex].ssl.peer_cert) != -1)
+#else
+ if(x509parse_cert_info(buffer, sizeof(buffer), (char *)"* ",
+ ssl_get_peer_cert(&(connssl->ssl))) != -1)
+#endif
+ infof(data, "Dumping cert info:\n%s\n", buffer);
+ }
+
+ connssl->connecting_state = ssl_connect_3;
+ infof(data, "SSL connected\n");
+
+ return CURLE_OK;
+}
+
+static CURLcode
+polarssl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ struct SessionHandle *data = conn->data;
+ void *old_ssl_sessionid = NULL;
+ ssl_session *our_ssl_sessionid = &conn->ssl[sockindex].ssn ;
+ int incache;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+ /* Save the current session data for possible re-use */
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ void *new_session = malloc(sizeof(ssl_session));
+
+ if(new_session) {
+ memcpy(new_session, our_ssl_sessionid,
+ sizeof(ssl_session));
+
+ retcode = Curl_ssl_addsessionid(conn, new_session,
+ sizeof(ssl_session));
+ }
+ else {
+ retcode = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(retcode) {
+ failf(data, "failed to store ssl session");
+ return retcode;
+ }
+ }
+
+ connssl->connecting_state = ssl_connect_done;
+
+ return CURLE_OK;
+}
+
+static ssize_t polarssl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+
+ ret = ssl_write(&conn->ssl[sockindex].ssl,
+ (unsigned char *)mem, len);
+
+ if(ret < 0) {
+ *curlcode = (ret == POLARSSL_ERR_NET_WANT_WRITE) ?
+ CURLE_AGAIN : CURLE_SEND_ERROR;
+ ret = -1;
+ }
+
+ return ret;
+}
+
+void Curl_polarssl_close_all(struct SessionHandle *data)
+{
+ (void)data;
+}
+
+void Curl_polarssl_close(struct connectdata *conn, int sockindex)
+{
+ rsa_free(&conn->ssl[sockindex].rsa);
+ x509_free(&conn->ssl[sockindex].clicert);
+ x509_free(&conn->ssl[sockindex].cacert);
+ x509_crl_free(&conn->ssl[sockindex].crl);
+ ssl_free(&conn->ssl[sockindex].ssl);
+}
+
+static ssize_t polarssl_recv(struct connectdata *conn,
+ int num,
+ char *buf,
+ size_t buffersize,
+ CURLcode *curlcode)
+{
+ int ret = -1;
+ ssize_t len = -1;
+
+ memset(buf, 0, buffersize);
+ ret = ssl_read(&conn->ssl[num].ssl, (unsigned char *)buf, buffersize);
+
+ if(ret <= 0) {
+ if(ret == POLARSSL_ERR_SSL_PEER_CLOSE_NOTIFY)
+ return 0;
+
+ *curlcode = (ret == POLARSSL_ERR_NET_WANT_READ) ?
+ CURLE_AGAIN : CURLE_RECV_ERROR;
+ return -1;
+ }
+
+ len = ret;
+
+ return len;
+}
+
+void Curl_polarssl_session_free(void *ptr)
+{
+ free(ptr);
+}
+
+size_t Curl_polarssl_version(char *buffer, size_t size)
+{
+ unsigned int version = version_get_number();
+ return snprintf(buffer, size, "PolarSSL/%d.%d.%d", version>>24,
+ (version>>16)&0xff, (version>>8)&0xff);
+}
+
+static CURLcode
+polarssl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ retcode = polarssl_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if
+ * this connection is part of a multi handle and this loop would
+ * execute again. This permits the owner of a multi handle to
+ * abort a connection attempt before step2 has completed while
+ * ensuring that a client using select() or epoll() will always
+ * have a valid fdset to wait on.
+ */
+ retcode = polarssl_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+ if(ssl_connect_3==connssl->connecting_state) {
+ retcode = polarssl_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done==connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = polarssl_recv;
+ conn->send[sockindex] = polarssl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_polarssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return polarssl_connect_common(conn, sockindex, TRUE, done);
+}
+
+
+CURLcode
+Curl_polarssl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = polarssl_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+/*
+ * return 0 error initializing SSL
+ * return 1 SSL initialized successfully
+ */
+int polarssl_init(void)
+{
+ return polarsslthreadlock_thread_setup();
+}
+
+void polarssl_cleanup(void)
+{
+ (void)polarsslthreadlock_thread_cleanup();
+}
+
+#endif /* USE_POLARSSL */
diff --git a/libs/libcurl/src/polarssl.h b/libs/libcurl/src/polarssl.h
new file mode 100644
index 0000000000..af3b28b89a
--- /dev/null
+++ b/libs/libcurl/src/polarssl.h
@@ -0,0 +1,67 @@
+#ifndef HEADER_CURL_POLARSSL_H
+#define HEADER_CURL_POLARSSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ *
+ * 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_POLARSSL
+
+/* Called on first use PolarSSL, setup threading if supported */
+int polarssl_init(void);
+void polarssl_cleanup(void);
+
+
+CURLcode Curl_polarssl_connect(struct connectdata *conn, int sockindex);
+
+CURLcode Curl_polarssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* tell PolarSSL to close down all open information regarding connections (and
+ thus session ID caching etc) */
+void Curl_polarssl_close_all(struct SessionHandle *data);
+
+ /* close a SSL connection */
+void Curl_polarssl_close(struct connectdata *conn, int sockindex);
+
+void Curl_polarssl_session_free(void *ptr);
+size_t Curl_polarssl_version(char *buffer, size_t size);
+int Curl_polarssl_shutdown(struct connectdata *conn, int sockindex);
+
+/* API setup for PolarSSL */
+#define curlssl_init() polarssl_init()
+#define curlssl_cleanup() polarssl_cleanup()
+#define curlssl_connect Curl_polarssl_connect
+#define curlssl_connect_nonblocking Curl_polarssl_connect_nonblocking
+#define curlssl_session_free(x) Curl_polarssl_session_free(x)
+#define curlssl_close_all Curl_polarssl_close_all
+#define curlssl_close Curl_polarssl_close
+#define curlssl_shutdown(x,y) 0
+#define curlssl_set_engine(x,y) (x=x, y=y, CURLE_NOT_BUILT_IN)
+#define curlssl_set_engine_default(x) (x=x, CURLE_NOT_BUILT_IN)
+#define curlssl_engines_list(x) (x=x, (struct curl_slist *)NULL)
+#define curlssl_version Curl_polarssl_version
+#define curlssl_check_cxn(x) (x=x, -1)
+#define curlssl_data_pending(x,y) (x=x, y=y, 0)
+
+#endif /* USE_POLARSSL */
+#endif /* HEADER_CURL_POLARSSL_H */
diff --git a/libs/libcurl/src/polarssl_threadlock.c b/libs/libcurl/src/polarssl_threadlock.c
new file mode 100644
index 0000000000..ad18715375
--- /dev/null
+++ b/libs/libcurl/src/polarssl_threadlock.c
@@ -0,0 +1,156 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, 2011, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ * 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.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#if defined(USE_POLARSSL) && \
+ (defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32))
+
+#if defined(USE_THREADS_POSIX)
+# ifdef HAVE_PTHREAD_H
+# include <pthread.h>
+# endif
+#elif defined(USE_THREADS_WIN32)
+# ifdef HAVE_PROCESS_H
+# include <process.h>
+# endif
+#endif
+
+#include "polarssl_threadlock.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"
+
+/* number of thread locks */
+#define NUMT 2
+
+/* This array will store all of the mutexes available to PolarSSL. */
+static POLARSSL_MUTEX_T *mutex_buf = NULL;
+
+int polarsslthreadlock_thread_setup(void)
+{
+ int i;
+ int ret;
+
+ mutex_buf = malloc(NUMT * sizeof(POLARSSL_MUTEX_T));
+ if(!mutex_buf)
+ return 0; /* error, no number of threads defined */
+
+#ifdef HAVE_PTHREAD_H
+ for(i = 0; i < NUMT; i++) {
+ ret = pthread_mutex_init(&mutex_buf[i], NULL);
+ if(ret)
+ return 0; /* pthread_mutex_init failed */
+ }
+#elif defined(HAVE_PROCESS_H)
+ for(i = 0; i < NUMT; i++) {
+ mutex_buf[i] = CreateMutex(0, FALSE, 0);
+ if(mutex_buf[i] == 0)
+ return 0; /* CreateMutex failed */
+ }
+#endif /* HAVE_PTHREAD_H */
+
+ return 1; /* OK */
+}
+
+int polarsslthreadlock_thread_cleanup(void)
+{
+ int i;
+ int ret;
+
+ if(!mutex_buf)
+ return 0; /* error, no threads locks defined */
+
+#ifdef HAVE_PTHREAD_H
+ for(i = 0; i < NUMT; i++) {
+ ret = pthread_mutex_destroy(&mutex_buf[i]);
+ if(ret)
+ return 0; /* pthread_mutex_destroy failed */
+ }
+#elif defined(HAVE_PROCESS_H)
+ for(i = 0; i < NUMT; i++) {
+ ret = CloseHandle(mutex_buf[i]);
+ if(!ret)
+ return 0; /* CloseHandle failed */
+ }
+#endif /* HAVE_PTHREAD_H */
+ free(mutex_buf);
+ mutex_buf = NULL;
+
+ return 1; /* OK */
+}
+
+int polarsslthreadlock_lock_function(int n)
+{
+ int ret;
+#ifdef HAVE_PTHREAD_H
+ if(n < NUMT) {
+ ret = pthread_mutex_lock(&mutex_buf[n]);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_lock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#elif defined(HAVE_PROCESS_H)
+ if(n < NUMT) {
+ ret = (WaitForSingleObject(mutex_buf[n], INFINITE)==WAIT_FAILED?1:0);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_lock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#endif /* HAVE_PTHREAD_H */
+ return 1; /* OK */
+}
+
+int polarsslthreadlock_unlock_function(int n)
+{
+ int ret;
+#ifdef HAVE_PTHREAD_H
+ if(n < NUMT) {
+ ret = pthread_mutex_unlock(&mutex_buf[n]);
+ if(ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_unlock_function failed\n"));
+ return 0; /* pthread_mutex_unlock failed */
+ }
+ }
+#elif defined(HAVE_PROCESS_H)
+ if(n < NUMT) {
+ ret = ReleaseMutex(mutex_buf[n]);
+ if(!ret) {
+ DEBUGF(fprintf(stderr,
+ "Error: polarsslthreadlock_unlock_function failed\n"));
+ return 0; /* pthread_mutex_lock failed */
+ }
+ }
+#endif /* HAVE_PTHREAD_H */
+ return 1; /* OK */
+}
+
+#endif /* USE_POLARSSL */
diff --git a/libs/libcurl/src/polarssl_threadlock.h b/libs/libcurl/src/polarssl_threadlock.h
new file mode 100644
index 0000000000..b67b3f9abd
--- /dev/null
+++ b/libs/libcurl/src/polarssl_threadlock.h
@@ -0,0 +1,53 @@
+#ifndef HEADER_CURL_POLARSSL_THREADLOCK_H
+#define HEADER_CURL_POLARSSL_THREADLOCK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010, Hoi-Ho Chan, <hoiho.chan@gmail.com>
+ * 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.
+ *
+ ***************************************************************************/
+#include "curl_setup.h"
+
+#ifdef USE_POLARSSL
+
+#if defined(USE_THREADS_POSIX)
+# define POLARSSL_MUTEX_T pthread_mutex_t
+#elif defined(USE_THREADS_WIN32)
+# define POLARSSL_MUTEX_T HANDLE
+#endif
+
+#if defined(USE_THREADS_POSIX) || defined(USE_THREADS_WIN32)
+
+int polarsslthreadlock_thread_setup(void);
+int polarsslthreadlock_thread_cleanup(void);
+int polarsslthreadlock_lock_function(int n);
+int polarsslthreadlock_unlock_function(int n);
+
+#else
+
+#define polarsslthreadlock_thread_setup() 1
+#define polarsslthreadlock_thread_cleanup() 1
+#define polarsslthreadlock_lock_function(x) 1
+#define polarsslthreadlock_unlock_function(x) 1
+
+#endif /* USE_THREADS_POSIX || USE_THREADS_WIN32 */
+
+#endif /* USE_POLARSSL */
+
+#endif /* HEADER_CURL_POLARSSL_THREADLOCK_H */
diff --git a/libs/libcurl/src/pop3.c b/libs/libcurl/src/pop3.c
new file mode 100644
index 0000000000..a771933840
--- /dev/null
+++ b/libs/libcurl/src/pop3.c
@@ -0,0 +1,1996 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ * RFC1734 POP3 Authentication
+ * RFC1939 POP3 protocol
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2384 POP URL Scheme
+ * RFC2449 POP3 Extension Mechanism
+ * RFC2595 Using TLS with IMAP, POP3 and ACAP
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC5034 POP3 SASL Authentication Mechanism
+ * RFC6749 OAuth 2.0 Authorization Framework
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_POP3
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "pop3.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "curl_sasl.h"
+#include "curl_md5.h"
+#include "warnless.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"
+
+/* Local API functions */
+static CURLcode pop3_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode pop3_do(struct connectdata *conn, bool *done);
+static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode pop3_connect(struct connectdata *conn, bool *done);
+static CURLcode pop3_disconnect(struct connectdata *conn, bool dead);
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done);
+static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode pop3_setup_connection(struct connectdata *conn);
+static CURLcode pop3_parse_url_options(struct connectdata *conn);
+static CURLcode pop3_parse_url_path(struct connectdata *conn);
+static CURLcode pop3_parse_custom_request(struct connectdata *conn);
+
+/*
+ * POP3 protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3 = {
+ "POP3", /* scheme */
+ pop3_setup_connection, /* setup_connection */
+ pop3_do, /* do_it */
+ pop3_done, /* done */
+ ZERO_NULL, /* do_more */
+ pop3_connect, /* connect_it */
+ pop3_multi_statemach, /* connecting */
+ pop3_doing, /* doing */
+ pop3_getsock, /* proto_getsock */
+ pop3_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ pop3_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3, /* defport */
+ CURLPROTO_POP3, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * POP3S protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_pop3s = {
+ "POP3S", /* scheme */
+ pop3_setup_connection, /* setup_connection */
+ pop3_do, /* do_it */
+ pop3_done, /* done */
+ ZERO_NULL, /* do_more */
+ pop3_connect, /* connect_it */
+ pop3_multi_statemach, /* connecting */
+ pop3_doing, /* doing */
+ pop3_getsock, /* proto_getsock */
+ pop3_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ pop3_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3S, /* defport */
+ CURLPROTO_POP3 | CURLPROTO_POP3S, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL
+ | PROTOPT_NOURLQUERY /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed POP3 protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3_proxy = {
+ "POP3", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed POP3S protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_pop3s_proxy = {
+ "POP3S", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_POP3S, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+#ifdef USE_SSL
+static void pop3_to_pop3s(struct connectdata *conn)
+{
+ conn->handler = &Curl_handler_pop3s;
+}
+#else
+#define pop3_to_pop3s(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * pop3_endofresp()
+ *
+ * Checks for an ending POP3 status code at the start of the given string, but
+ * also detects the APOP timestamp from the server greeting and various
+ * capabilities from the CAPA response including the supported authentication
+ * types and allowed SASL mechanisms.
+ */
+static bool pop3_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ size_t wordlen;
+ size_t i;
+
+ /* Do we have an error response? */
+ if(len >= 4 && !memcmp("-ERR", line, 4)) {
+ *resp = '-';
+
+ return TRUE;
+ }
+
+ /* Are we processing servergreet responses? */
+ if(pop3c->state == POP3_SERVERGREET) {
+ /* Look for the APOP timestamp */
+ if(len >= 3 && line[len - 3] == '>') {
+ for(i = 0; i < len - 3; ++i) {
+ if(line[i] == '<') {
+ /* Calculate the length of the timestamp */
+ size_t timestamplen = len - 2 - i;
+
+ /* Allocate some memory for the timestamp */
+ pop3c->apoptimestamp = (char *)calloc(1, timestamplen + 1);
+
+ if(!pop3c->apoptimestamp)
+ break;
+
+ /* Copy the timestamp */
+ memcpy(pop3c->apoptimestamp, line + i, timestamplen);
+ pop3c->apoptimestamp[timestamplen] = '\0';
+ break;
+ }
+ }
+ }
+ }
+ /* Are we processing CAPA command responses? */
+ else if(pop3c->state == POP3_CAPA) {
+ /* Do we have the terminating line? */
+ if(len >= 1 && !memcmp(line, ".", 1)) {
+ *resp = '+';
+
+ return TRUE;
+ }
+
+ /* Does the server support the STLS capability? */
+ if(len >= 4 && !memcmp(line, "STLS", 4))
+ pop3c->tls_supported = TRUE;
+
+ /* Does the server support clear text authentication? */
+ else if(len >= 4 && !memcmp(line, "USER", 4))
+ pop3c->authtypes |= POP3_TYPE_CLEARTEXT;
+
+ /* Does the server support APOP authentication? */
+ else if(len >= 4 && !memcmp(line, "APOP", 4))
+ pop3c->authtypes |= POP3_TYPE_APOP;
+
+ /* Does the server support SASL based authentication? */
+ else if(len >= 5 && !memcmp(line, "SASL ", 5)) {
+ pop3c->authtypes |= POP3_TYPE_SASL;
+
+ /* Advance past the SASL keyword */
+ line += 5;
+ len -= 5;
+
+ /* Loop through the data line */
+ for(;;) {
+ while(len &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ len--;
+ }
+
+ if(!len)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Test the word for a matching authentication mechanism */
+ if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
+ pop3c->authmechs |= SASL_MECH_LOGIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
+ pop3c->authmechs |= SASL_MECH_PLAIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
+ pop3c->authmechs |= SASL_MECH_CRAM_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
+ pop3c->authmechs |= SASL_MECH_DIGEST_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
+ pop3c->authmechs |= SASL_MECH_GSSAPI;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
+ pop3c->authmechs |= SASL_MECH_EXTERNAL;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
+ pop3c->authmechs |= SASL_MECH_NTLM;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
+ pop3c->authmechs |= SASL_MECH_XOAUTH2;
+
+ line += wordlen;
+ len -= wordlen;
+ }
+ }
+
+ return FALSE;
+ }
+
+ /* Do we have a command or continuation response? */
+ if((len >= 3 && !memcmp("+OK", line, 3)) ||
+ (len >= 1 && !memcmp("+", line, 1))) {
+ *resp = '+';
+
+ return TRUE;
+ }
+
+ return FALSE; /* Nothing for us */
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change POP3 state!
+ */
+static void state(struct connectdata *conn, pop3state newstate)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "STOP",
+ "SERVERGREET",
+ "CAPA",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTH_PLAIN",
+ "AUTH_LOGIN",
+ "AUTH_LOGIN_PASSWD",
+ "AUTH_CRAMMD5",
+ "AUTH_DIGESTMD5",
+ "AUTH_DIGESTMD5_RESP",
+ "AUTH_NTLM",
+ "AUTH_NTLM_TYPE2MSG",
+ "AUTH_XOAUTH2",
+ "AUTH_FINAL",
+ "APOP",
+ "USER",
+ "PASS",
+ "COMMAND",
+ "QUIT",
+ /* LAST */
+ };
+
+ if(pop3c->state != newstate)
+ infof(conn->data, "POP3 %p state change from %s to %s\n",
+ (void *)pop3c, names[pop3c->state], names[newstate]);
+#endif
+
+ pop3c->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_capa()
+ *
+ * Sends the CAPA command in order to obtain a list of server side supported
+ * capabilities.
+ */
+static CURLcode pop3_perform_capa(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ pop3c->authmechs = 0; /* No known authentication mechanisms yet */
+ pop3c->authused = 0; /* Clear the authentication mechanism used */
+ pop3c->tls_supported = FALSE; /* Clear the TLS capability */
+
+ /* Send the CAPA command */
+ result = Curl_pp_sendf(&pop3c->pp, "%s", "CAPA");
+
+ if(!result)
+ state(conn, POP3_CAPA);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode pop3_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STLS command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "STLS");
+
+ if(!result)
+ state(conn, POP3_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode pop3_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+
+ if(!result) {
+ if(pop3c->state != POP3_UPGRADETLS)
+ state(conn, POP3_UPGRADETLS);
+
+ if(pop3c->ssldone) {
+ pop3_to_pop3s(conn);
+ result = pop3_perform_capa(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_user()
+ *
+ * Sends a clear text USER command to authenticate with.
+ */
+static CURLcode pop3_perform_user(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, POP3_STOP);
+
+ return result;
+ }
+
+ /* Send the USER command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "USER %s",
+ conn->user ? conn->user : "");
+ if(!result)
+ state(conn, POP3_USER);
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/***********************************************************************
+ *
+ * pop3_perform_apop()
+ *
+ * Sends an APOP command to authenticate with.
+ */
+static CURLcode pop3_perform_apop(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ size_t i;
+ MD5_context *ctxt;
+ unsigned char digest[MD5_DIGEST_LEN];
+ char secret[2 * MD5_DIGEST_LEN + 1];
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, POP3_STOP);
+
+ return result;
+ }
+
+ /* Create the digest */
+ ctxt = Curl_MD5_init(Curl_DIGEST_MD5);
+ if(!ctxt)
+ return CURLE_OUT_OF_MEMORY;
+
+ Curl_MD5_update(ctxt, (const unsigned char *) pop3c->apoptimestamp,
+ curlx_uztoui(strlen(pop3c->apoptimestamp)));
+
+ Curl_MD5_update(ctxt, (const unsigned char *) conn->passwd,
+ curlx_uztoui(strlen(conn->passwd)));
+
+ /* Finalise the digest */
+ Curl_MD5_final(ctxt, digest);
+
+ /* Convert the calculated 16 octet digest into a 32 byte hex string */
+ for(i = 0; i < MD5_DIGEST_LEN; i++)
+ snprintf(&secret[2 * i], 3, "%02x", digest[i]);
+
+ result = Curl_pp_sendf(&pop3c->pp, "APOP %s %s", conn->user, secret);
+
+ if(!result)
+ state(conn, POP3_APOP);
+
+ return result;
+}
+#endif
+
+/***********************************************************************
+ *
+ * pop3_perform_authenticate()
+ *
+ * Sends an AUTH command allowing the client to login with the appropriate
+ * SASL authentication mechanism.
+ *
+ * Additionally, the function will perform fallback to APOP and USER commands
+ * should a common mechanism not be available between the client and server.
+ */
+static CURLcode pop3_perform_authenticate(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ const char *mech = NULL;
+ char *initresp = NULL;
+ size_t len = 0;
+ pop3state state1 = POP3_STOP;
+ pop3state state2 = POP3_STOP;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, POP3_STOP);
+
+ return result;
+ }
+
+ /* Calculate the supported authentication mechanism by decreasing order of
+ security */
+ if(pop3c->authtypes & POP3_TYPE_SASL) {
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if((pop3c->authmechs & SASL_MECH_DIGEST_MD5) &&
+ (pop3c->prefmech & SASL_MECH_DIGEST_MD5)) {
+ mech = SASL_MECH_STRING_DIGEST_MD5;
+ state1 = POP3_AUTH_DIGESTMD5;
+ pop3c->authused = SASL_MECH_DIGEST_MD5;
+ }
+ else if((pop3c->authmechs & SASL_MECH_CRAM_MD5) &&
+ (pop3c->prefmech & SASL_MECH_CRAM_MD5)) {
+ mech = SASL_MECH_STRING_CRAM_MD5;
+ state1 = POP3_AUTH_CRAMMD5;
+ pop3c->authused = SASL_MECH_CRAM_MD5;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if((pop3c->authmechs & SASL_MECH_NTLM) &&
+ (pop3c->prefmech & SASL_MECH_NTLM)) {
+ mech = SASL_MECH_STRING_NTLM;
+ state1 = POP3_AUTH_NTLM;
+ state2 = POP3_AUTH_NTLM_TYPE2MSG;
+ pop3c->authused = SASL_MECH_NTLM;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &initresp, &len);
+ }
+ else
+#endif
+ if(((pop3c->authmechs & SASL_MECH_XOAUTH2) &&
+ (pop3c->prefmech & SASL_MECH_XOAUTH2) &&
+ (pop3c->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
+ mech = SASL_MECH_STRING_XOAUTH2;
+ state1 = POP3_AUTH_XOAUTH2;
+ state2 = POP3_AUTH_FINAL;
+ pop3c->authused = SASL_MECH_XOAUTH2;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &initresp, &len);
+ }
+ else if((pop3c->authmechs & SASL_MECH_LOGIN) &&
+ (pop3c->prefmech & SASL_MECH_LOGIN)) {
+ mech = SASL_MECH_STRING_LOGIN;
+ state1 = POP3_AUTH_LOGIN;
+ state2 = POP3_AUTH_LOGIN_PASSWD;
+ pop3c->authused = SASL_MECH_LOGIN;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_login_message(conn->data, conn->user,
+ &initresp, &len);
+ }
+ else if((pop3c->authmechs & SASL_MECH_PLAIN) &&
+ (pop3c->prefmech & SASL_MECH_PLAIN)) {
+ mech = SASL_MECH_STRING_PLAIN;
+ state1 = POP3_AUTH_PLAIN;
+ state2 = POP3_AUTH_FINAL;
+ pop3c->authused = SASL_MECH_PLAIN;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_plain_message(conn->data, conn->user,
+ conn->passwd, &initresp,
+ &len);
+ }
+ }
+
+ if(!result) {
+ if(mech && (pop3c->preftype & POP3_TYPE_SASL)) {
+ /* Perform SASL based authentication */
+ if(initresp &&
+ 8 + strlen(mech) + len <= 255) { /* AUTH <mech> ...<crlf> */
+ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s %s", mech, initresp);
+
+ if(!result)
+ state(conn, state2);
+ }
+ else {
+ result = Curl_pp_sendf(&pop3c->pp, "AUTH %s", mech);
+
+ if(!result)
+ state(conn, state1);
+ }
+
+ Curl_safefree(initresp);
+ }
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ else if((pop3c->authtypes & POP3_TYPE_APOP) &&
+ (pop3c->preftype & POP3_TYPE_APOP))
+ /* Perform APOP authentication */
+ result = pop3_perform_apop(conn);
+#endif
+ else if((pop3c->authtypes & POP3_TYPE_CLEARTEXT) &&
+ (pop3c->preftype & POP3_TYPE_CLEARTEXT))
+ /* Perform clear text authentication */
+ result = pop3_perform_user(conn);
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_command()
+ *
+ * Sends a POP3 based command.
+ */
+static CURLcode pop3_perform_command(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *command = NULL;
+
+ /* Calculate the default command */
+ if(pop3->id[0] == '\0' || conn->data->set.ftp_list_only) {
+ command = "LIST";
+
+ if(pop3->id[0] != '\0')
+ /* Message specific LIST so skip the BODY transfer */
+ pop3->transfer = FTPTRANSFER_INFO;
+ }
+ else
+ command = "RETR";
+
+ /* Send the command */
+ if(pop3->id[0] != '\0')
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s %s",
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command), pop3->id);
+ else
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s",
+ (pop3->custom && pop3->custom[0] != '\0' ?
+ pop3->custom : command));
+
+ if(!result)
+ state(conn, POP3_COMMAND);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform_quit()
+ *
+ * Performs the quit action prior to sclose() be called.
+ */
+static CURLcode pop3_perform_quit(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the QUIT command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "QUIT");
+
+ if(!result)
+ state(conn, POP3_QUIT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode pop3_state_servergreet_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Got unexpected pop3-server response");
+ result = CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+ else
+ result = pop3_perform_capa(conn);
+
+ return result;
+}
+
+/* For CAPA responses */
+static CURLcode pop3_state_capa_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+')
+ result = pop3_perform_user(conn);
+ else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(pop3c->tls_supported)
+ /* Switch to TLS connection now */
+ result = pop3_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = pop3_perform_authenticate(conn);
+ else {
+ failf(data, "STLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = pop3_perform_authenticate(conn);
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode pop3_state_starttls_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied. %c", pop3code);
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = pop3_perform_authenticate(conn);
+ }
+ else
+ result = pop3_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For AUTH PLAIN (without initial response) responses */
+static CURLcode pop3_state_auth_plain_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *plainauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied. %c", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_plain_message(data, conn->user, conn->passwd,
+ &plainauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(plainauth) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", plainauth);
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ Curl_safefree(plainauth);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTH LOGIN (without initial response) responses */
+static CURLcode pop3_state_auth_login_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authuser = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the user message */
+ result = Curl_sasl_create_login_message(data, conn->user,
+ &authuser, &len);
+
+ /* Send the user */
+ if(!result) {
+ if(authuser) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authuser);
+
+ if(!result)
+ state(conn, POP3_AUTH_LOGIN_PASSWD);
+ }
+
+ Curl_safefree(authuser);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTH LOGIN user entry responses */
+static CURLcode pop3_state_auth_login_password_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authpasswd = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the password message */
+ result = Curl_sasl_create_login_message(data, conn->passwd,
+ &authpasswd, &len);
+
+ /* Send the password */
+ if(!result) {
+ if(authpasswd) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", authpasswd);
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ Curl_safefree(authpasswd);
+ }
+ }
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* For AUTH CRAM-MD5 responses */
+static CURLcode pop3_state_auth_cram_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Terminate the challenge */
+ if(*chlg64 != '=') {
+ for(len = strlen(chlg64); len--;)
+ if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
+ chlg64[len] != '\t')
+ break;
+
+ if(++len) {
+ chlg64[len] = '\0';
+ }
+ }
+
+ /* Create the response message */
+ result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
+ conn->passwd, &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTH DIGEST-MD5 challenge responses */
+static CURLcode pop3_state_auth_digest_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 2; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Create the response message */
+ result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
+ conn->passwd, "pop",
+ &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, POP3_AUTH_DIGESTMD5_RESP);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTH DIGEST-MD5 challenge-response responses */
+static CURLcode pop3_state_auth_digest_resp_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Authentication failed: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Send an empty response */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", "");
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ return result;
+}
+#endif
+
+#ifdef USE_NTLM
+/* For AUTH NTLM (without initial response) responses */
+static CURLcode pop3_state_auth_ntlm_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *type1msg = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-1 message */
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &type1msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type1msg) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type1msg);
+
+ if(!result)
+ state(conn, POP3_AUTH_NTLM_TYPE2MSG);
+ }
+
+ Curl_safefree(type1msg);
+ }
+ }
+
+ return result;
+}
+
+/* For NTLM type-2 responses (sent in reponse to our type-1 message) */
+static CURLcode pop3_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *type3msg = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-3 message */
+ result = Curl_sasl_create_ntlm_type3_message(data,
+ data->state.buffer + 2,
+ conn->user, conn->passwd,
+ &conn->ntlm,
+ &type3msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type3msg) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", type3msg);
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ Curl_safefree(type3msg);
+ }
+ }
+
+ return result;
+}
+#endif
+
+/* For AUTH XOAUTH2 (without initial response) responses */
+static CURLcode pop3_state_auth_xoauth2_resp(struct connectdata *conn,
+ int pop3code, pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *xoauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &xoauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(xoauth) {
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "%s", xoauth);
+
+ if(!result)
+ state(conn, POP3_AUTH_FINAL);
+ }
+
+ Curl_safefree(xoauth);
+ }
+ }
+
+ return result;
+}
+
+/* For final responses to the AUTH sequence */
+static CURLcode pop3_state_auth_final_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Authentication failed: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* For APOP responses */
+static CURLcode pop3_state_apop_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Authentication failed: %d", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+#endif
+
+/* For USER responses */
+static CURLcode pop3_state_user_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied. %c", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* Send the PASS command */
+ result = Curl_pp_sendf(&conn->proto.pop3c.pp, "PASS %s",
+ conn->passwd ? conn->passwd : "");
+ if(!result)
+ state(conn, POP3_PASS);
+
+ return result;
+}
+
+/* For PASS responses */
+static CURLcode pop3_state_pass_resp(struct connectdata *conn, int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ failf(data, "Access denied. %c", pop3code);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+
+/* For command responses */
+static CURLcode pop3_state_command_resp(struct connectdata *conn,
+ int pop3code,
+ pop3state instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+
+ (void)instate; /* no use for this yet */
+
+ if(pop3code != '+') {
+ state(conn, POP3_STOP);
+ return CURLE_RECV_ERROR;
+ }
+
+ /* This 'OK' line ends with a CR LF pair which is the two first bytes of the
+ EOB string so count this is two matching bytes. This is necessary to make
+ the code detect the EOB if the only data than comes now is %2e CR LF like
+ when there is no body to return. */
+ pop3c->eob = 2;
+
+ /* But since this initial CR LF pair is not part of the actual body, we set
+ the strip counter here so that these bytes won't be delivered. */
+ pop3c->strip = 2;
+
+ if(pop3->transfer == FTPTRANSFER_BODY) {
+ /* POP3 download */
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
+
+ if(pp->cache) {
+ /* The header "cache" contains a bunch of data that is actually body
+ content so send it as such. Note that there may even be additional
+ "headers" after the body */
+
+ if(!data->set.opt_no_body) {
+ result = Curl_pop3_write(conn, pp->cache, pp->cache_size);
+ if(result)
+ return result;
+ }
+
+ /* Free the cache */
+ Curl_safefree(pp->cache);
+
+ /* Reset the cache size */
+ pp->cache_size = 0;
+ }
+ }
+
+ /* End of DO phase */
+ state(conn, POP3_STOP);
+
+ return result;
+}
+
+static CURLcode pop3_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ int pop3code;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not POP3 */
+ if(pop3c->state == POP3_UPGRADETLS)
+ return pop3_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &pop3code, &nread);
+ if(result)
+ return result;
+
+ if(pop3code) {
+ /* We have now received a full POP3 server response */
+ switch(pop3c->state) {
+ case POP3_SERVERGREET:
+ result = pop3_state_servergreet_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_CAPA:
+ result = pop3_state_capa_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_STARTTLS:
+ result = pop3_state_starttls_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_PLAIN:
+ result = pop3_state_auth_plain_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_LOGIN:
+ result = pop3_state_auth_login_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_LOGIN_PASSWD:
+ result = pop3_state_auth_login_password_resp(conn, pop3code,
+ pop3c->state);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case POP3_AUTH_CRAMMD5:
+ result = pop3_state_auth_cram_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_DIGESTMD5:
+ result = pop3_state_auth_digest_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_DIGESTMD5_RESP:
+ result = pop3_state_auth_digest_resp_resp(conn, pop3code, pop3c->state);
+ break;
+#endif
+
+#ifdef USE_NTLM
+ case POP3_AUTH_NTLM:
+ result = pop3_state_auth_ntlm_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_NTLM_TYPE2MSG:
+ result = pop3_state_auth_ntlm_type2msg_resp(conn, pop3code,
+ pop3c->state);
+ break;
+#endif
+
+ case POP3_AUTH_XOAUTH2:
+ result = pop3_state_auth_xoauth2_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_AUTH_FINAL:
+ result = pop3_state_auth_final_resp(conn, pop3code, pop3c->state);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case POP3_APOP:
+ result = pop3_state_apop_resp(conn, pop3code, pop3c->state);
+ break;
+#endif
+
+ case POP3_USER:
+ result = pop3_state_user_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_PASS:
+ result = pop3_state_pass_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_COMMAND:
+ result = pop3_state_command_resp(conn, pop3code, pop3c->state);
+ break;
+
+ case POP3_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, POP3_STOP);
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode pop3_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !pop3c->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &pop3c->ssldone);
+ if(result || !pop3c->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&pop3c->pp, FALSE);
+ *done = (pop3c->state == POP3_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode pop3_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ while(pop3c->state != POP3_STOP && !result)
+ result = Curl_pp_statemach(&pop3c->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the POP3 struct for the current SessionHandle if
+ required */
+static CURLcode pop3_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3;
+
+ pop3 = data->req.protop = calloc(sizeof(struct POP3), 1);
+ if(!pop3)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the POP3 "protocol connect" and "doing" phases only */
+static int pop3_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.pop3c.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * pop3_connect()
+ *
+ * This function 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 if not.
+ */
+static CURLcode pop3_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ struct pingpong *pp = &pop3c->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in POP3 */
+ conn->bits.close = FALSE;
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = pop3_statemach_act;
+ pp->endofresp = pop3_endofresp;
+ pp->conn = conn;
+
+ /* Set the default preferred authentication type and mechanism */
+ pop3c->preftype = POP3_TYPE_ANY;
+ pop3c->prefmech = SASL_AUTH_ANY;
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = pop3_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, POP3_SERVERGREET);
+
+ result = pop3_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode pop3_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+
+ (void)premature;
+
+ if(!pop3)
+ /* When the easy handle is removed from the multi interface while libcurl
+ is still trying to resolve the host name, the POP3 struct is not yet
+ initialized. However, the removal action calls Curl_done() which in
+ turn calls this function, so we simply return success. */
+ return CURLE_OK;
+
+ if(status) {
+ conn->bits.close = TRUE; /* marked for closure */
+ result = status; /* use the already set error code */
+ }
+
+ /* Cleanup our per-request based variables */
+ Curl_safefree(pop3->id);
+ Curl_safefree(pop3->custom);
+
+ /* Clear the transfer mode for the next request */
+ pop3->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_perform()
+ *
+ * This is the actual DO function for POP3. Get a message/listing according to
+ * the options previously setup.
+ */
+static CURLcode pop3_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is POP3 and no proxy */
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ struct POP3 *pop3 = conn->data->req.protop;
+ pop3->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Start the first command in the DO phase */
+ result = pop3_perform_command(conn);
+ if(result)
+ return result;
+
+ /* Run the state-machine */
+ result = pop3_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (pop3_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode pop3_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ /* Parse the URL path */
+ result = pop3_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Parse the custom request */
+ result = pop3_parse_custom_request(conn);
+ if(result)
+ return result;
+
+ result = pop3_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_disconnect()
+ *
+ * Disconnect from an POP3 server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode pop3_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The POP3 session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && pop3c->pp.conn)
+ if(!pop3_perform_quit(conn))
+ (void)pop3_block_statemach(conn); /* ignore errors on QUIT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&pop3c->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, pop3c->authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(pop3c->apoptimestamp);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode pop3_dophase_done(struct connectdata *conn, bool connected)
+{
+ (void)conn;
+ (void)connected;
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode pop3_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = pop3_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = pop3_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode pop3_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct SessionHandle *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ /* Carry out the perform */
+ result = pop3_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = pop3_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode pop3_setup_connection(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+
+ /* Initialise the POP3 layer */
+ CURLcode result = pop3_init(conn);
+ if(result)
+ return result;
+
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel POP3 operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_pop3)
+ conn->handler = &Curl_handler_pop3_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_pop3s_proxy;
+#else
+ failf(data, "POP3S not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* set it up as an HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+#else
+ failf(data, "POP3 over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode pop3_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ const char *options = conn->options;
+ const char *ptr = options;
+
+ if(options) {
+ const char *key = ptr;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ if(strnequal(key, "AUTH", 4)) {
+ const char *value = ptr + 1;
+
+ if(strequal(value, "*")) {
+ pop3c->preftype = POP3_TYPE_ANY;
+ pop3c->prefmech = SASL_AUTH_ANY;
+ }
+ else if(strequal(value, "+APOP")) {
+ pop3c->preftype = POP3_TYPE_APOP;
+ pop3c->prefmech = SASL_AUTH_NONE;
+ }
+ else if(strequal(value, SASL_MECH_STRING_LOGIN)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_LOGIN;
+ }
+ else if(strequal(value, SASL_MECH_STRING_PLAIN)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_PLAIN;
+ }
+ else if(strequal(value, SASL_MECH_STRING_CRAM_MD5)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_CRAM_MD5;
+ }
+ else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_DIGEST_MD5;
+ }
+ else if(strequal(value, SASL_MECH_STRING_GSSAPI)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_GSSAPI;
+ }
+ else if(strequal(value, SASL_MECH_STRING_NTLM)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_NTLM;
+ }
+ else if(strequal(value, SASL_MECH_STRING_XOAUTH2)) {
+ pop3c->preftype = POP3_TYPE_SASL;
+ pop3c->prefmech = SASL_MECH_XOAUTH2;
+ }
+ else {
+ pop3c->preftype = POP3_TYPE_NONE;
+ pop3c->prefmech = SASL_AUTH_NONE;
+ }
+ }
+ else
+ result = CURLE_URL_MALFORMAT;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode pop3_parse_url_path(struct connectdata *conn)
+{
+ /* The POP3 struct is already initialised in pop3_connect() */
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *path = data->state.path;
+
+ /* URL decode the path for the message ID */
+ return Curl_urldecode(data, path, 0, &pop3->id, NULL, TRUE);
+}
+
+/***********************************************************************
+ *
+ * pop3_parse_custom_request()
+ *
+ * Parse the custom request.
+ */
+static CURLcode pop3_parse_custom_request(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct POP3 *pop3 = data->req.protop;
+ const char *custom = data->set.str[STRING_CUSTOMREQUEST];
+
+ /* URL decode the custom request */
+ if(custom)
+ result = Curl_urldecode(data, custom, 0, &pop3->custom, NULL, TRUE);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * Curl_pop3_write()
+ *
+ * This function scans the body after the end-of-body and writes everything
+ * until the end is found.
+ */
+CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread)
+{
+ /* This code could be made into a special function in the handler struct */
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SingleRequest *k = &data->req;
+
+ struct pop3_conn *pop3c = &conn->proto.pop3c;
+ bool strip_dot = FALSE;
+ size_t last = 0;
+ size_t i;
+
+ /* Search through the buffer looking for the end-of-body marker which is
+ 5 bytes (0d 0a 2e 0d 0a). Note that a line starting with a dot matches
+ the eob so the server will have prefixed it with an extra dot which we
+ need to strip out. Additionally the marker could of course be spread out
+ over 5 different data chunks. */
+ for(i = 0; i < nread; i++) {
+ size_t prev = pop3c->eob;
+
+ switch(str[i]) {
+ case 0x0d:
+ if(pop3c->eob == 0) {
+ pop3c->eob++;
+
+ if(i) {
+ /* Write out the body part that didn't match */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+ i - last);
+
+ if(result)
+ return result;
+
+ last = i;
+ }
+ }
+ else if(pop3c->eob == 3)
+ pop3c->eob++;
+ else
+ /* If the character match wasn't at position 0 or 3 then restart the
+ pattern matching */
+ pop3c->eob = 1;
+ break;
+
+ case 0x0a:
+ if(pop3c->eob == 1 || pop3c->eob == 4)
+ pop3c->eob++;
+ else
+ /* If the character match wasn't at position 1 or 4 then start the
+ search again */
+ pop3c->eob = 0;
+ break;
+
+ case 0x2e:
+ if(pop3c->eob == 2)
+ pop3c->eob++;
+ else if(pop3c->eob == 3) {
+ /* We have an extra dot after the CRLF which we need to strip off */
+ strip_dot = TRUE;
+ pop3c->eob = 0;
+ }
+ else
+ /* If the character match wasn't at position 2 then start the search
+ again */
+ pop3c->eob = 0;
+ break;
+
+ default:
+ pop3c->eob = 0;
+ break;
+ }
+
+ /* Did we have a partial match which has subsequently failed? */
+ if(prev && prev >= pop3c->eob) {
+ /* Strip can only be non-zero for the very first mismatch after CRLF
+ and then both prev and strip are equal and nothing will be output
+ below */
+ while(prev && pop3c->strip) {
+ prev--;
+ pop3c->strip--;
+ }
+
+ if(prev) {
+ /* If the partial match was the CRLF and dot then only write the CRLF
+ as the server would have inserted the dot */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char*)POP3_EOB,
+ strip_dot ? prev - 1 : prev);
+
+ if(result)
+ return result;
+
+ last = i;
+ strip_dot = FALSE;
+ }
+ }
+ }
+
+ if(pop3c->eob == POP3_EOB_LEN) {
+ /* We have a full match so the transfer is done, however we must transfer
+ the CRLF at the start of the EOB as this is considered to be part of the
+ message as per RFC-1939, sect. 3 */
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)POP3_EOB, 2);
+
+ k->keepon &= ~KEEP_RECV;
+ pop3c->eob = 0;
+
+ return result;
+ }
+
+ if(pop3c->eob)
+ /* While EOB is matching nothing should be output */
+ return CURLE_OK;
+
+ if(nread - last) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, &str[last],
+ nread - last);
+ }
+
+ return result;
+}
+
+#endif /* CURL_DISABLE_POP3 */
diff --git a/libs/libcurl/src/pop3.h b/libs/libcurl/src/pop3.h
new file mode 100644
index 0000000000..7bc7744955
--- /dev/null
+++ b/libs/libcurl/src/pop3.h
@@ -0,0 +1,105 @@
+#ifndef HEADER_CURL_POP3_H
+#define HEADER_CURL_POP3_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 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 "pingpong.h"
+
+/****************************************************************************
+ * POP3 unique setup
+ ***************************************************************************/
+typedef enum {
+ POP3_STOP, /* do nothing state, stops the state machine */
+ POP3_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ POP3_CAPA,
+ POP3_STARTTLS,
+ POP3_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ POP3_AUTH_PLAIN,
+ POP3_AUTH_LOGIN,
+ POP3_AUTH_LOGIN_PASSWD,
+ POP3_AUTH_CRAMMD5,
+ POP3_AUTH_DIGESTMD5,
+ POP3_AUTH_DIGESTMD5_RESP,
+ POP3_AUTH_NTLM,
+ POP3_AUTH_NTLM_TYPE2MSG,
+ POP3_AUTH_XOAUTH2,
+ POP3_AUTH_FINAL,
+ POP3_APOP,
+ POP3_USER,
+ POP3_PASS,
+ POP3_COMMAND,
+ POP3_QUIT,
+ POP3_LAST /* never used */
+} pop3state;
+
+/* This POP3 struct is used in the SessionHandle. All POP3 data that is
+ connection-oriented must be in pop3_conn to properly deal with the fact that
+ perhaps the SessionHandle is changed between the times the connection is
+ used. */
+struct POP3 {
+ curl_pp_transfer transfer;
+ char *id; /* Message ID */
+ char *custom; /* Custom Request */
+};
+
+/* pop3_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct pop3_conn {
+ struct pingpong pp;
+ pop3state state; /* Always use pop3.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ size_t eob; /* Number of bytes of the EOB (End Of Body) that
+ have been received so far */
+ size_t strip; /* Number of bytes from the start to ignore as
+ non-body */
+ unsigned int authtypes; /* Accepted authentication types */
+ unsigned int authmechs; /* Accepted SASL authentication mechanisms */
+ unsigned int preftype; /* Preferred authentication type */
+ unsigned int prefmech; /* Preferred SASL authentication mechanism */
+ unsigned int authused; /* SASL auth mechanism used for the connection */
+ char *apoptimestamp; /* APOP timestamp from the server greeting */
+ bool tls_supported; /* StartTLS capability supported by server */
+};
+
+extern const struct Curl_handler Curl_handler_pop3;
+extern const struct Curl_handler Curl_handler_pop3s;
+
+/* Authentication type flags */
+#define POP3_TYPE_CLEARTEXT (1 << 0)
+#define POP3_TYPE_APOP (1 << 1)
+#define POP3_TYPE_SASL (1 << 2)
+
+/* Authentication type values */
+#define POP3_TYPE_NONE 0
+#define POP3_TYPE_ANY ~0
+
+/* This is the 5-bytes End-Of-Body marker for POP3 */
+#define POP3_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define POP3_EOB_LEN 5
+
+/* This function scans the body after the end-of-body and writes everything
+ * until the end is found */
+CURLcode Curl_pop3_write(struct connectdata *conn, char *str, size_t nread);
+
+#endif /* HEADER_CURL_POP3_H */
diff --git a/libs/libcurl/src/progress.c b/libs/libcurl/src/progress.c
new file mode 100644
index 0000000000..dac7f8d6ec
--- /dev/null
+++ b/libs/libcurl/src/progress.c
@@ -0,0 +1,483 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "urldata.h"
+#include "sendf.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* Provide a string that is 2 + 1 + 2 + 1 + 2 = 8 letters long (plus the zero
+ byte) */
+static void time2str(char *r, curl_off_t seconds)
+{
+ curl_off_t d, h, m, s;
+ if(seconds <= 0) {
+ strcpy(r, "--:--:--");
+ return;
+ }
+ h = seconds / CURL_OFF_T_C(3600);
+ if(h <= CURL_OFF_T_C(99)) {
+ m = (seconds - (h*CURL_OFF_T_C(3600))) / CURL_OFF_T_C(60);
+ s = (seconds - (h*CURL_OFF_T_C(3600))) - (m*CURL_OFF_T_C(60));
+ snprintf(r, 9, "%2" FORMAT_OFF_T ":%02" FORMAT_OFF_T ":%02" FORMAT_OFF_T,
+ h, m, s);
+ }
+ else {
+ /* this equals to more than 99 hours, switch to a more suitable output
+ format to fit within the limits. */
+ d = seconds / CURL_OFF_T_C(86400);
+ h = (seconds - (d*CURL_OFF_T_C(86400))) / CURL_OFF_T_C(3600);
+ if(d <= CURL_OFF_T_C(999))
+ snprintf(r, 9, "%3" FORMAT_OFF_T "d %02" FORMAT_OFF_T "h", d, h);
+ else
+ snprintf(r, 9, "%7" FORMAT_OFF_T "d", d);
+ }
+}
+
+/* The point of this function would be to return a string of the input data,
+ but never longer than 5 columns (+ one zero byte).
+ Add suffix k, M, G when suitable... */
+static char *max5data(curl_off_t bytes, char *max5)
+{
+#define ONE_KILOBYTE CURL_OFF_T_C(1024)
+#define ONE_MEGABYTE (CURL_OFF_T_C(1024) * ONE_KILOBYTE)
+#define ONE_GIGABYTE (CURL_OFF_T_C(1024) * ONE_MEGABYTE)
+#define ONE_TERABYTE (CURL_OFF_T_C(1024) * ONE_GIGABYTE)
+#define ONE_PETABYTE (CURL_OFF_T_C(1024) * ONE_TERABYTE)
+
+ if(bytes < CURL_OFF_T_C(100000))
+ snprintf(max5, 6, "%5" FORMAT_OFF_T, bytes);
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_KILOBYTE)
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "k", bytes/ONE_KILOBYTE);
+
+ else if(bytes < CURL_OFF_T_C(100) * ONE_MEGABYTE)
+ /* 'XX.XM' is good as long as we're less than 100 megs */
+ snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "M",
+ bytes/ONE_MEGABYTE,
+ (bytes%ONE_MEGABYTE) / (ONE_MEGABYTE/CURL_OFF_T_C(10)) );
+
+#if (CURL_SIZEOF_CURL_OFF_T > 4)
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_MEGABYTE)
+ /* 'XXXXM' is good until we're at 10000MB or above */
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "M", bytes/ONE_MEGABYTE);
+
+ else if(bytes < CURL_OFF_T_C(100) * ONE_GIGABYTE)
+ /* 10000 MB - 100 GB, we show it as XX.XG */
+ snprintf(max5, 6, "%2" FORMAT_OFF_T ".%0" FORMAT_OFF_T "G",
+ bytes/ONE_GIGABYTE,
+ (bytes%ONE_GIGABYTE) / (ONE_GIGABYTE/CURL_OFF_T_C(10)) );
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_GIGABYTE)
+ /* up to 10000GB, display without decimal: XXXXG */
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "G", bytes/ONE_GIGABYTE);
+
+ else if(bytes < CURL_OFF_T_C(10000) * ONE_TERABYTE)
+ /* up to 10000TB, display without decimal: XXXXT */
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "T", bytes/ONE_TERABYTE);
+
+ else
+ /* up to 10000PB, display without decimal: XXXXP */
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "P", bytes/ONE_PETABYTE);
+
+ /* 16384 petabytes (16 exabytes) is the maximum a 64 bit unsigned number
+ can hold, but our data type is signed so 8192PB will be the maximum. */
+
+#else
+
+ else
+ snprintf(max5, 6, "%4" FORMAT_OFF_T "M", bytes/ONE_MEGABYTE);
+
+#endif
+
+ return max5;
+}
+
+/*
+
+ New proposed interface, 9th of February 2000:
+
+ pgrsStartNow() - sets start time
+ pgrsSetDownloadSize(x) - known expected download size
+ pgrsSetUploadSize(x) - known expected upload size
+ pgrsSetDownloadCounter() - amount of data currently downloaded
+ pgrsSetUploadCounter() - amount of data currently uploaded
+ pgrsUpdate() - show progress
+ pgrsDone() - transfer complete
+
+*/
+
+int Curl_pgrsDone(struct connectdata *conn)
+{
+ int rc;
+ struct SessionHandle *data = conn->data;
+ data->progress.lastshow=0;
+ rc = Curl_pgrsUpdate(conn); /* the final (forced) update */
+ if(rc)
+ return rc;
+
+ if(!(data->progress.flags & PGRS_HIDE) &&
+ !data->progress.callback)
+ /* only output if we don't use a progress callback and we're not
+ * hidden */
+ fprintf(data->set.err, "\n");
+
+ data->progress.speeder_c = 0; /* reset the progress meter display */
+ return 0;
+}
+
+/* reset all times except redirect, and reset the known transfer sizes */
+void Curl_pgrsResetTimesSizes(struct SessionHandle *data)
+{
+ data->progress.t_nslookup = 0.0;
+ data->progress.t_connect = 0.0;
+ data->progress.t_pretransfer = 0.0;
+ data->progress.t_starttransfer = 0.0;
+
+ Curl_pgrsSetDownloadSize(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+}
+
+void Curl_pgrsTime(struct SessionHandle *data, timerid timer)
+{
+ struct timeval now = Curl_tvnow();
+
+ switch(timer) {
+ default:
+ case TIMER_NONE:
+ /* mistake filter */
+ break;
+ case TIMER_STARTSINGLE:
+ /* This is set at the start of a single fetch */
+ data->progress.t_startsingle = now;
+ break;
+
+ case TIMER_STARTACCEPT:
+ data->progress.t_acceptdata = Curl_tvnow();
+ break;
+
+ case TIMER_NAMELOOKUP:
+ data->progress.t_nslookup =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_CONNECT:
+ data->progress.t_connect =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_APPCONNECT:
+ data->progress.t_appconnect =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_PRETRANSFER:
+ data->progress.t_pretransfer =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_STARTTRANSFER:
+ data->progress.t_starttransfer =
+ Curl_tvdiff_secs(now, data->progress.t_startsingle);
+ break;
+ case TIMER_POSTRANSFER:
+ /* this is the normal end-of-transfer thing */
+ break;
+ case TIMER_REDIRECT:
+ data->progress.t_redirect = Curl_tvdiff_secs(now, data->progress.start);
+ break;
+ }
+}
+
+void Curl_pgrsStartNow(struct SessionHandle *data)
+{
+ data->progress.speeder_c = 0; /* reset the progress meter display */
+ data->progress.start = Curl_tvnow();
+ /* clear all bits except HIDE and HEADERS_OUT */
+ data->progress.flags &= PGRS_HIDE|PGRS_HEADERS_OUT;
+}
+
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size)
+{
+ data->progress.downloaded = size;
+}
+
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size)
+{
+ data->progress.uploaded = size;
+}
+
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size)
+{
+ data->progress.size_dl = size;
+ if(size >= 0)
+ data->progress.flags |= PGRS_DL_SIZE_KNOWN;
+ else
+ data->progress.flags &= ~PGRS_DL_SIZE_KNOWN;
+}
+
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size)
+{
+ data->progress.size_ul = size;
+ if(size >= 0)
+ data->progress.flags |= PGRS_UL_SIZE_KNOWN;
+ else
+ data->progress.flags &= ~PGRS_UL_SIZE_KNOWN;
+}
+
+/*
+ * Curl_pgrsUpdate() returns 0 for success or the value returned by the
+ * progress callback!
+ */
+int Curl_pgrsUpdate(struct connectdata *conn)
+{
+ struct timeval now;
+ int result;
+ char max5[6][10];
+ curl_off_t dlpercen=0;
+ curl_off_t ulpercen=0;
+ curl_off_t total_percen=0;
+ curl_off_t total_transfer;
+ curl_off_t total_expected_transfer;
+ curl_off_t timespent;
+ struct SessionHandle *data = conn->data;
+ int nowindex = data->progress.speeder_c% CURR_TIME;
+ int checkindex;
+ int countindex; /* amount of seconds stored in the speeder array */
+ char time_left[10];
+ char time_total[10];
+ char time_spent[10];
+ curl_off_t ulestimate=0;
+ curl_off_t dlestimate=0;
+ curl_off_t total_estimate;
+ bool shownow=FALSE;
+
+ now = Curl_tvnow(); /* what time is it */
+
+ /* The time spent so far (from the start) */
+ data->progress.timespent =
+ (double)(now.tv_sec - data->progress.start.tv_sec) +
+ (double)(now.tv_usec - data->progress.start.tv_usec)/1000000.0;
+ timespent = (curl_off_t)data->progress.timespent;
+
+ /* The average download speed this far */
+ data->progress.dlspeed = (curl_off_t)
+ ((double)data->progress.downloaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
+
+ /* The average upload speed this far */
+ data->progress.ulspeed = (curl_off_t)
+ ((double)data->progress.uploaded/
+ (data->progress.timespent>0?data->progress.timespent:1));
+
+ /* Calculations done at most once a second, unless end is reached */
+ if(data->progress.lastshow != (long)now.tv_sec) {
+ shownow = TRUE;
+
+ data->progress.lastshow = now.tv_sec;
+
+ /* Let's do the "current speed" thing, which should use the fastest
+ of the dl/ul speeds. Store the faster speed at entry 'nowindex'. */
+ data->progress.speeder[ nowindex ] =
+ data->progress.downloaded>data->progress.uploaded?
+ data->progress.downloaded:data->progress.uploaded;
+
+ /* remember the exact time for this moment */
+ data->progress.speeder_time [ nowindex ] = now;
+
+ /* advance our speeder_c counter, which is increased every time we get
+ here and we expect it to never wrap as 2^32 is a lot of seconds! */
+ data->progress.speeder_c++;
+
+ /* figure out how many index entries of data we have stored in our speeder
+ array. With N_ENTRIES filled in, we have about N_ENTRIES-1 seconds of
+ transfer. Imagine, after one second we have filled in two entries,
+ after two seconds we've filled in three entries etc. */
+ countindex = ((data->progress.speeder_c>=CURR_TIME)?
+ CURR_TIME:data->progress.speeder_c) - 1;
+
+ /* first of all, we don't do this if there's no counted seconds yet */
+ if(countindex) {
+ long span_ms;
+
+ /* Get the index position to compare with the 'nowindex' position.
+ Get the oldest entry possible. While we have less than CURR_TIME
+ entries, the first entry will remain the oldest. */
+ checkindex = (data->progress.speeder_c>=CURR_TIME)?
+ data->progress.speeder_c%CURR_TIME:0;
+
+ /* Figure out the exact time for the time span */
+ span_ms = Curl_tvdiff(now,
+ data->progress.speeder_time[checkindex]);
+ if(0 == span_ms)
+ span_ms=1; /* at least one millisecond MUST have passed */
+
+ /* Calculate the average speed the last 'span_ms' milliseconds */
+ {
+ curl_off_t amount = data->progress.speeder[nowindex]-
+ data->progress.speeder[checkindex];
+
+ if(amount > CURL_OFF_T_C(4294967) /* 0xffffffff/1000 */)
+ /* the 'amount' value is bigger than would fit in 32 bits if
+ multiplied with 1000, so we use the double math for this */
+ data->progress.current_speed = (curl_off_t)
+ ((double)amount/((double)span_ms/1000.0));
+ else
+ /* the 'amount' value is small enough to fit within 32 bits even
+ when multiplied with 1000 */
+ data->progress.current_speed = amount*CURL_OFF_T_C(1000)/span_ms;
+ }
+ }
+ else
+ /* the first second we use the main average */
+ data->progress.current_speed =
+ (data->progress.ulspeed>data->progress.dlspeed)?
+ data->progress.ulspeed:data->progress.dlspeed;
+
+ } /* Calculations end */
+
+ if(!(data->progress.flags & PGRS_HIDE)) {
+ /* progress meter has not been shut off */
+
+ if(data->set.fxferinfo) {
+ /* There's a callback set, call that */
+ result= data->set.fxferinfo(data->set.progress_client,
+ data->progress.size_dl,
+ data->progress.downloaded,
+ data->progress.size_ul,
+ data->progress.uploaded);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+ else if(data->set.fprogress) {
+ /* The older deprecated callback is set, call that */
+ result= data->set.fprogress(data->set.progress_client,
+ (double)data->progress.size_dl,
+ (double)data->progress.downloaded,
+ (double)data->progress.size_ul,
+ (double)data->progress.uploaded);
+ if(result)
+ failf(data, "Callback aborted");
+ return result;
+ }
+
+ if(!shownow)
+ /* only show the internal progress meter once per second */
+ return 0;
+
+ /* If there's no external callback set, use internal code to show
+ progress */
+
+ if(!(data->progress.flags & PGRS_HEADERS_OUT)) {
+ if(data->state.resume_from) {
+ fprintf(data->set.err,
+ "** Resuming transfer from byte position %" FORMAT_OFF_T "\n",
+ data->state.resume_from);
+ }
+ fprintf(data->set.err,
+ " %% Total %% Received %% Xferd Average Speed "
+ "Time Time Time Current\n"
+ " Dload Upload "
+ "Total Spent Left Speed\n");
+ data->progress.flags |= PGRS_HEADERS_OUT; /* headers are shown */
+ }
+
+ /* Figure out the estimated time of arrival for the upload */
+ if((data->progress.flags & PGRS_UL_SIZE_KNOWN) &&
+ (data->progress.ulspeed > CURL_OFF_T_C(0))) {
+ ulestimate = data->progress.size_ul / data->progress.ulspeed;
+
+ if(data->progress.size_ul > CURL_OFF_T_C(10000))
+ ulpercen = data->progress.uploaded /
+ (data->progress.size_ul/CURL_OFF_T_C(100));
+ else if(data->progress.size_ul > CURL_OFF_T_C(0))
+ ulpercen = (data->progress.uploaded*100) /
+ data->progress.size_ul;
+ }
+
+ /* ... and the download */
+ if((data->progress.flags & PGRS_DL_SIZE_KNOWN) &&
+ (data->progress.dlspeed > CURL_OFF_T_C(0))) {
+ dlestimate = data->progress.size_dl / data->progress.dlspeed;
+
+ if(data->progress.size_dl > CURL_OFF_T_C(10000))
+ dlpercen = data->progress.downloaded /
+ (data->progress.size_dl/CURL_OFF_T_C(100));
+ else if(data->progress.size_dl > CURL_OFF_T_C(0))
+ dlpercen = (data->progress.downloaded*100) /
+ data->progress.size_dl;
+ }
+
+ /* Now figure out which of them is slower and use that one for the
+ total estimate! */
+ total_estimate = ulestimate>dlestimate?ulestimate:dlestimate;
+
+ /* create the three time strings */
+ time2str(time_left, total_estimate > 0?(total_estimate - timespent):0);
+ time2str(time_total, total_estimate);
+ time2str(time_spent, timespent);
+
+ /* Get the total amount of data expected to get transferred */
+ total_expected_transfer =
+ (data->progress.flags & PGRS_UL_SIZE_KNOWN?
+ data->progress.size_ul:data->progress.uploaded)+
+ (data->progress.flags & PGRS_DL_SIZE_KNOWN?
+ data->progress.size_dl:data->progress.downloaded);
+
+ /* We have transferred this much so far */
+ total_transfer = data->progress.downloaded + data->progress.uploaded;
+
+ /* Get the percentage of data transferred so far */
+ if(total_expected_transfer > CURL_OFF_T_C(10000))
+ total_percen = total_transfer /
+ (total_expected_transfer/CURL_OFF_T_C(100));
+ else if(total_expected_transfer > CURL_OFF_T_C(0))
+ total_percen = (total_transfer*100) / total_expected_transfer;
+
+ fprintf(data->set.err,
+ "\r"
+ "%3" FORMAT_OFF_T " %s "
+ "%3" FORMAT_OFF_T " %s "
+ "%3" FORMAT_OFF_T " %s %s %s %s %s %s %s",
+ total_percen, /* 3 letters */ /* total % */
+ max5data(total_expected_transfer, max5[2]), /* total size */
+ dlpercen, /* 3 letters */ /* rcvd % */
+ max5data(data->progress.downloaded, max5[0]), /* rcvd size */
+ ulpercen, /* 3 letters */ /* xfer % */
+ max5data(data->progress.uploaded, max5[1]), /* xfer size */
+ max5data(data->progress.dlspeed, max5[3]), /* avrg dl speed */
+ max5data(data->progress.ulspeed, max5[4]), /* avrg ul speed */
+ time_total, /* 8 letters */ /* total time */
+ time_spent, /* 8 letters */ /* time spent */
+ time_left, /* 8 letters */ /* time left */
+ max5data(data->progress.current_speed, max5[5]) /* current speed */
+ );
+
+ /* we flush the output stream to make it appear as soon as possible */
+ fflush(data->set.err);
+
+ } /* !(data->progress.flags & PGRS_HIDE) */
+
+ return 0;
+}
diff --git a/libs/libcurl/src/progress.h b/libs/libcurl/src/progress.h
new file mode 100644
index 0000000000..f97fef9961
--- /dev/null
+++ b/libs/libcurl/src/progress.h
@@ -0,0 +1,72 @@
+#ifndef HEADER_CURL_PROGRESS_H
+#define HEADER_CURL_PROGRESS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 "timeval.h"
+
+
+typedef enum {
+ TIMER_NONE,
+ TIMER_NAMELOOKUP,
+ TIMER_CONNECT,
+ TIMER_APPCONNECT,
+ TIMER_PRETRANSFER,
+ TIMER_STARTTRANSFER,
+ TIMER_POSTRANSFER,
+ TIMER_STARTSINGLE,
+ TIMER_STARTACCEPT,
+ TIMER_REDIRECT,
+ TIMER_LAST /* must be last */
+} timerid;
+
+int Curl_pgrsDone(struct connectdata *);
+void Curl_pgrsStartNow(struct SessionHandle *data);
+void Curl_pgrsSetDownloadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadSize(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetDownloadCounter(struct SessionHandle *data, curl_off_t size);
+void Curl_pgrsSetUploadCounter(struct SessionHandle *data, curl_off_t size);
+int Curl_pgrsUpdate(struct connectdata *);
+void Curl_pgrsResetTimesSizes(struct SessionHandle *data);
+void Curl_pgrsTime(struct SessionHandle *data, timerid timer);
+
+
+/* Don't show progress for sizes smaller than: */
+#define LEAST_SIZE_PROGRESS BUFSIZE
+
+#define PROGRESS_DOWNLOAD (1<<0)
+#define PROGRESS_UPLOAD (1<<1)
+#define PROGRESS_DOWN_AND_UP (PROGRESS_UPLOAD | PROGRESS_DOWNLOAD)
+
+#define PGRS_SHOW_DL (1<<0)
+#define PGRS_SHOW_UL (1<<1)
+#define PGRS_DONE_DL (1<<2)
+#define PGRS_DONE_UL (1<<3)
+#define PGRS_HIDE (1<<4)
+#define PGRS_UL_SIZE_KNOWN (1<<5)
+#define PGRS_DL_SIZE_KNOWN (1<<6)
+
+#define PGRS_HEADERS_OUT (1<<7) /* set when the headers have been written */
+
+
+#endif /* HEADER_CURL_PROGRESS_H */
+
diff --git a/libs/libcurl/src/qssl.c b/libs/libcurl/src/qssl.c
new file mode 100644
index 0000000000..b8a8daecac
--- /dev/null
+++ b/libs/libcurl/src/qssl.c
@@ -0,0 +1,521 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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_QSOSSL
+
+#include <qsossl.h>
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "qssl.h"
+#include "sslgen.h"
+#include "connect.h" /* for the connect timeout */
+#include "select.h"
+#include "x509asn1.h"
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+
+int Curl_qsossl_init(void)
+
+{
+ /* Nothing to do here. We must have connection data to initialize ssl, so
+ * defer.
+ */
+
+ return 1;
+}
+
+
+void Curl_qsossl_cleanup(void)
+
+{
+ /* Nothing to do. */
+}
+
+
+static CURLcode Curl_qsossl_init_session(struct SessionHandle * data)
+
+{
+ int rc;
+ char * certname;
+ SSLInit initstr;
+ SSLInitApp initappstr;
+
+ /* Initialize the job for SSL according to the current parameters.
+ * QsoSSL offers two ways to do it: SSL_Init_Application() that uses an
+ * application identifier to select certificates in the main certificate
+ * store, and SSL_Init() that uses named keyring files and a password.
+ * It is not possible to have different keyrings for the CAs and the
+ * local certificate. We thus use the certificate name to identify the
+ * keyring if given, else the CA file name.
+ * If the key file name is given, it is taken as the password for the
+ * keyring in certificate file.
+ * We first try to SSL_Init_Application(), then SSL_Init() if it failed.
+ */
+
+ certname = data->set.str[STRING_CERT];
+
+ if(!certname) {
+ certname = data->set.str[STRING_SSL_CAFILE];
+
+ if(!certname)
+ return CURLE_OK; /* Use previous setup. */
+ }
+
+ memset((char *) &initappstr, 0, sizeof initappstr);
+ initappstr.applicationID = certname;
+ initappstr.applicationIDLen = strlen(certname);
+ initappstr.protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
+ initappstr.sessionType = SSL_REGISTERED_AS_CLIENT;
+ rc = SSL_Init_Application(&initappstr);
+
+ if(rc == SSL_ERROR_NOT_REGISTERED) {
+ initstr.keyringFileName = certname;
+ initstr.keyringPassword = data->set.str[STRING_KEY];
+ initstr.cipherSuiteList = NULL; /* Use default. */
+ initstr.cipherSuiteListLen = 0;
+ rc = SSL_Init(&initstr);
+ }
+
+ switch (rc) {
+
+ case 0: /* No error. */
+ break;
+
+ case SSL_ERROR_IO:
+ failf(data, "SSL_Init() I/O error: %s", strerror(errno));
+ return CURLE_SSL_CONNECT_ERROR;
+
+ case SSL_ERROR_BAD_CIPHER_SUITE:
+ return CURLE_SSL_CIPHER;
+
+ case SSL_ERROR_KEYPASSWORD_EXPIRED:
+ case SSL_ERROR_NOT_REGISTERED:
+ return CURLE_SSL_CONNECT_ERROR;
+
+ case SSL_ERROR_NO_KEYRING:
+ return CURLE_SSL_CACERT;
+
+ case SSL_ERROR_CERT_EXPIRED:
+ return CURLE_SSL_CERTPROBLEM;
+
+ default:
+ failf(data, "SSL_Init(): %s", SSL_Strerror(rc, NULL));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ return CURLE_OK;
+}
+
+
+static CURLcode Curl_qsossl_create(struct connectdata * conn, int sockindex)
+
+{
+ SSLHandle * h;
+ struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+
+ h = SSL_Create(conn->sock[sockindex], SSL_ENCRYPT);
+
+ if(!h) {
+ failf(conn->data, "SSL_Create() I/O error: %s", strerror(errno));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->handle = h;
+ return CURLE_OK;
+}
+
+
+static int Curl_qsossl_trap_cert(SSLHandle * h)
+
+{
+ return 1; /* Accept certificate. */
+}
+
+
+static CURLcode Curl_qsossl_handshake(struct connectdata * conn, int sockindex)
+
+{
+ int rc;
+ struct SessionHandle * data = conn->data;
+ struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+ SSLHandle * h = connssl->handle;
+ long timeout_ms;
+
+ h->exitPgm = data->set.ssl.verifypeer? NULL: Curl_qsossl_trap_cert;
+
+ /* figure out how long time we should wait at maximum */
+ timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout_ms < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* SSL_Handshake() timeout resolution is second, so round up. */
+ h->timeout = (timeout_ms + 1000 - 1) / 1000;
+
+ /* Set-up protocol. */
+
+ switch (data->set.ssl.version) {
+
+ default:
+ case CURL_SSLVERSION_DEFAULT:
+ h->protocol = SSL_VERSION_CURRENT; /* TLSV1 compat. SSLV[23]. */
+ break;
+
+ case CURL_SSLVERSION_TLSv1:
+ h->protocol = TLS_VERSION_1;
+ break;
+
+ case CURL_SSLVERSION_SSLv2:
+ h->protocol = SSL_VERSION_2;
+ break;
+
+ case CURL_SSLVERSION_SSLv3:
+ h->protocol = SSL_VERSION_3;
+ break;
+ }
+
+ h->peerCert = NULL;
+ h->peerCertLen = 0;
+ rc = SSL_Handshake(h, SSL_HANDSHAKE_AS_CLIENT);
+
+ switch (rc) {
+
+ case 0: /* No error. */
+ break;
+
+ case SSL_ERROR_BAD_CERTIFICATE:
+ case SSL_ERROR_BAD_CERT_SIG:
+ case SSL_ERROR_NOT_TRUSTED_ROOT:
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ case SSL_ERROR_BAD_CIPHER_SUITE:
+ case SSL_ERROR_NO_CIPHERS:
+ return CURLE_SSL_CIPHER;
+
+ case SSL_ERROR_CERTIFICATE_REJECTED:
+ case SSL_ERROR_CERT_EXPIRED:
+ case SSL_ERROR_NO_CERTIFICATE:
+ return CURLE_SSL_CERTPROBLEM;
+
+ case SSL_ERROR_IO:
+ failf(data, "SSL_Handshake() I/O error: %s", strerror(errno));
+ return CURLE_SSL_CONNECT_ERROR;
+
+ default:
+ failf(data, "SSL_Handshake(): %s", SSL_Strerror(rc, NULL));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ /* Verify host. */
+ rc = Curl_verifyhost(conn, h->peerCert, h->peerCert + h->peerCertLen);
+ if(rc != CURLE_OK)
+ return rc;
+
+ /* Gather certificate info. */
+ if(data->set.ssl.certinfo) {
+ if(Curl_ssl_init_certinfo(data, 1))
+ return CURLE_OUT_OF_MEMORY;
+ if(h->peerCert) {
+ rc = Curl_extract_certinfo(conn, 0, h->peerCert,
+ h->peerCert + h->peerCertLen);
+ if(rc != CURLE_OK)
+ return rc;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+
+static Curl_recv qsossl_recv;
+static Curl_send qsossl_send;
+
+CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex)
+
+{
+ struct SessionHandle * data = conn->data;
+ struct ssl_connect_data * connssl = &conn->ssl[sockindex];
+ int rc;
+
+ rc = Curl_qsossl_init_session(data);
+
+ if(rc == CURLE_OK) {
+ rc = Curl_qsossl_create(conn, sockindex);
+
+ if(rc == CURLE_OK) {
+ rc = Curl_qsossl_handshake(conn, sockindex);
+ if(rc != CURLE_OK)
+ SSL_Destroy(connssl->handle);
+ }
+ }
+
+ if(rc == CURLE_OK) {
+ conn->recv[sockindex] = qsossl_recv;
+ conn->send[sockindex] = qsossl_send;
+ connssl->state = ssl_connection_complete;
+ }
+ else {
+ connssl->handle = NULL;
+ connssl->use = FALSE;
+ connssl->state = ssl_connection_none;
+ }
+
+ return rc;
+}
+
+
+static int Curl_qsossl_close_one(struct ssl_connect_data * conn,
+ struct SessionHandle * data)
+
+{
+ int rc;
+
+ if(!conn->handle)
+ return 0;
+
+ rc = SSL_Destroy(conn->handle);
+
+ if(rc) {
+ if(rc == SSL_ERROR_IO) {
+ failf(data, "SSL_Destroy() I/O error: %s", strerror(errno));
+ return -1;
+ }
+
+ /* An SSL error. */
+ failf(data, "SSL_Destroy() returned error %s", SSL_Strerror(rc, NULL));
+ return -1;
+ }
+
+ conn->handle = NULL;
+ return 0;
+}
+
+
+void Curl_qsossl_close(struct connectdata *conn, int sockindex)
+
+{
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->use)
+ (void) Curl_qsossl_close_one(connssl, data);
+}
+
+
+int Curl_qsossl_close_all(struct SessionHandle * data)
+
+{
+ /* Unimplemented. */
+ (void) data;
+ return 0;
+}
+
+
+int Curl_qsossl_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;
+
+ if(Curl_qsossl_close_one(connssl, data))
+ return -1;
+
+ 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 SSL_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;
+}
+
+
+static ssize_t qsossl_send(struct connectdata * conn, int sockindex,
+ const void * mem, size_t len, CURLcode * curlcode)
+
+{
+ /* SSL_Write() is said to return 'int' while write() and send() returns
+ 'size_t' */
+ int rc;
+
+ rc = SSL_Write(conn->ssl[sockindex].handle, (void *) mem, (int) len);
+
+ if(rc < 0) {
+ switch(rc) {
+
+ case SSL_ERROR_BAD_STATE:
+ /* The operation did not complete; the same SSL I/O function
+ should be called again later. This is basically an EWOULDBLOCK
+ equivalent. */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+
+ case SSL_ERROR_IO:
+ switch (errno) {
+ case EWOULDBLOCK:
+ case EINTR:
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
+
+ failf(conn->data, "SSL_Write() I/O error: %s", strerror(errno));
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ /* An SSL error. */
+ failf(conn->data, "SSL_Write() returned error %s",
+ SSL_Strerror(rc, NULL));
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+
+ return (ssize_t) rc; /* number of bytes */
+}
+
+
+static ssize_t qsossl_recv(struct connectdata * conn, int num, char * buf,
+ size_t buffersize, CURLcode * curlcode)
+
+{
+ char error_buffer[120]; /* OpenSSL documents that this must be at
+ least 120 bytes long. */
+ unsigned long sslerror;
+ int buffsize;
+ int nread;
+
+ buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ nread = SSL_Read(conn->ssl[num].handle, buf, buffsize);
+
+ if(nread < 0) {
+ /* failed SSL_read */
+
+ switch (nread) {
+
+ case SSL_ERROR_BAD_STATE:
+ /* there's data pending, re-invoke SSL_Read(). */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+
+ case SSL_ERROR_IO:
+ switch (errno) {
+ case EWOULDBLOCK:
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ }
+
+ failf(conn->data, "SSL_Read() I/O error: %s", strerror(errno));
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+
+ default:
+ failf(conn->data, "SSL read error: %s", SSL_Strerror(nread, NULL));
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ return (ssize_t) nread;
+}
+
+
+size_t Curl_qsossl_version(char * buffer, size_t size)
+
+{
+ strncpy(buffer, "IBM OS/400 SSL", size);
+ return strlen(buffer);
+}
+
+
+int Curl_qsossl_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_QSOSSL */
diff --git a/libs/libcurl/src/qssl.h b/libs/libcurl/src/qssl.h
new file mode 100644
index 0000000000..1fb47b8299
--- /dev/null
+++ b/libs/libcurl/src/qssl.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_QSSL_H
+#define HEADER_CURL_QSSL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 qssl.c
+ */
+
+#include "urldata.h"
+
+#ifdef USE_QSOSSL
+int Curl_qsossl_init(void);
+void Curl_qsossl_cleanup(void);
+CURLcode Curl_qsossl_connect(struct connectdata * conn, int sockindex);
+void Curl_qsossl_close(struct connectdata *conn, int sockindex);
+int Curl_qsossl_close_all(struct SessionHandle * data);
+int Curl_qsossl_shutdown(struct connectdata * conn, int sockindex);
+
+size_t Curl_qsossl_version(char * buffer, size_t size);
+int Curl_qsossl_check_cxn(struct connectdata * cxn);
+
+/* API setup for QsoSSL */
+#define curlssl_init Curl_qsossl_init
+#define curlssl_cleanup Curl_qsossl_cleanup
+#define curlssl_connect Curl_qsossl_connect
+
+/* No session handling for QsoSSL */
+#define curlssl_session_free(x) Curl_nop_stmt
+#define curlssl_close_all Curl_qsossl_close_all
+#define curlssl_close Curl_qsossl_close
+#define curlssl_shutdown(x,y) Curl_qsossl_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_qsossl_version
+#define curlssl_check_cxn(x) Curl_qsossl_check_cxn(x)
+#define curlssl_data_pending(x,y) 0
+#endif /* USE_QSOSSL */
+
+#endif /* HEADER_CURL_QSSL_H */
diff --git a/libs/libcurl/src/rawstr.c b/libs/libcurl/src/rawstr.c
new file mode 100644
index 0000000000..e27dac4a80
--- /dev/null
+++ b/libs/libcurl/src/rawstr.c
@@ -0,0 +1,142 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "rawstr.h"
+
+/* Portable, consistent toupper (remember EBCDIC). Do not use toupper() because
+ its behavior is altered by the current locale. */
+char Curl_raw_toupper(char in)
+{
+ switch (in) {
+ case 'a':
+ return 'A';
+ case 'b':
+ return 'B';
+ case 'c':
+ return 'C';
+ case 'd':
+ return 'D';
+ case 'e':
+ return 'E';
+ case 'f':
+ return 'F';
+ case 'g':
+ return 'G';
+ case 'h':
+ return 'H';
+ case 'i':
+ return 'I';
+ case 'j':
+ return 'J';
+ case 'k':
+ return 'K';
+ case 'l':
+ return 'L';
+ case 'm':
+ return 'M';
+ case 'n':
+ return 'N';
+ case 'o':
+ return 'O';
+ case 'p':
+ return 'P';
+ case 'q':
+ return 'Q';
+ case 'r':
+ return 'R';
+ case 's':
+ return 'S';
+ case 't':
+ return 'T';
+ case 'u':
+ return 'U';
+ case 'v':
+ return 'V';
+ case 'w':
+ return 'W';
+ case 'x':
+ return 'X';
+ case 'y':
+ return 'Y';
+ case 'z':
+ return 'Z';
+ }
+ return in;
+}
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this. See http://daniel.haxx.se/blog/2008/10/15/strcasecmp-in-turkish/ for
+ * some further explanation to why this function is necessary.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+
+int Curl_raw_equal(const char *first, const char *second)
+{
+ while(*first && *second) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second))
+ /* get out of the loop as soon as they don't match */
+ break;
+ first++;
+ second++;
+ }
+ /* we do the comparison here (possibly again), just to make sure that if the
+ loop above is skipped because one of the strings reached zero, we must not
+ return this as a successful match */
+ return (Curl_raw_toupper(*first) == Curl_raw_toupper(*second));
+}
+
+int Curl_raw_nequal(const char *first, const char *second, size_t max)
+{
+ while(*first && *second && max) {
+ if(Curl_raw_toupper(*first) != Curl_raw_toupper(*second)) {
+ break;
+ }
+ max--;
+ first++;
+ second++;
+ }
+ if(0 == max)
+ return 1; /* they are equal this far */
+
+ return Curl_raw_toupper(*first) == Curl_raw_toupper(*second);
+}
+
+/* Copy an upper case version of the string from src to dest. The
+ * strings may overlap. No more than n characters of the string are copied
+ * (including any NUL) and the destination string will NOT be
+ * NUL-terminated if that limit is reached.
+ */
+void Curl_strntoupper(char *dest, const char *src, size_t n)
+{
+ if(n < 1)
+ return;
+
+ do {
+ *dest++ = Curl_raw_toupper(*src);
+ } while(*src++ && --n);
+}
diff --git a/libs/libcurl/src/rawstr.h b/libs/libcurl/src/rawstr.h
new file mode 100644
index 0000000000..b491460d0f
--- /dev/null
+++ b/libs/libcurl/src/rawstr.h
@@ -0,0 +1,47 @@
+#ifndef HEADER_CURL_RAWSTR_H
+#define HEADER_CURL_RAWSTR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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/curl.h>
+
+/*
+ * Curl_raw_equal() is for doing "raw" case insensitive strings. This is meant
+ * to be locale independent and only compare strings we know are safe for
+ * this.
+ *
+ * The function is capable of comparing a-z case insensitively even for
+ * non-ascii.
+ */
+int Curl_raw_equal(const char *first, const char *second);
+int Curl_raw_nequal(const char *first, const char *second, size_t max);
+
+char Curl_raw_toupper(char in);
+
+/* checkprefix() is a shorter version of the above, used when the first
+ argument is zero-byte terminated */
+#define checkprefix(a,b) Curl_raw_nequal(a,b,strlen(a))
+
+void Curl_strntoupper(char *dest, const char *src, size_t n);
+
+#endif /* HEADER_CURL_RAWSTR_H */
+
diff --git a/libs/libcurl/src/rtsp.c b/libs/libcurl/src/rtsp.c
new file mode 100644
index 0000000000..f7c6562a7b
--- /dev/null
+++ b/libs/libcurl/src/rtsp.c
@@ -0,0 +1,809 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_RTSP
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "http.h"
+#include "url.h"
+#include "progress.h"
+#include "rtsp.h"
+#include "rawstr.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "connect.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * TODO (general)
+ * -incoming server requests
+ * -server CSeq counter
+ * -digest authentication
+ * -connect thru proxy
+ * -pipelining?
+ */
+
+
+#define RTP_PKT_CHANNEL(p) ((int)((unsigned char)((p)[1])))
+
+#define RTP_PKT_LENGTH(p) ((((int)((unsigned char)((p)[2]))) << 8) | \
+ ((int)((unsigned char)((p)[3]))))
+
+/* protocol-specific functions set up to be called by the main engine */
+static CURLcode rtsp_do(struct connectdata *conn, bool *done);
+static CURLcode rtsp_done(struct connectdata *conn, CURLcode, bool premature);
+static CURLcode rtsp_connect(struct connectdata *conn, bool *done);
+static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead);
+
+static int rtsp_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+/*
+ * Parse and write out any available RTP data.
+ *
+ * nread: amount of data left after k->str. will be modified if RTP
+ * data is parsed and k->str is moved up
+ * readmore: whether or not the RTP parser needs more data right away
+ */
+static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *readmore);
+
+static CURLcode rtsp_setup_connection(struct connectdata *conn);
+
+
+/* this returns the socket to wait for in the DO and DOING state for the multi
+ interface and then we're always _sending_ a request and thus we wait for
+ the single socket to become writable only */
+static int rtsp_getsock_do(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ /* write mode */
+ (void)numsocks; /* unused, we trust it to be at least 1 */
+ socks[0] = conn->sock[FIRSTSOCKET];
+ return GETSOCK_WRITESOCK(0);
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len);
+
+
+/*
+ * RTSP handler interface.
+ */
+const struct Curl_handler Curl_handler_rtsp = {
+ "RTSP", /* scheme */
+ rtsp_setup_connection, /* setup_connection */
+ rtsp_do, /* do_it */
+ rtsp_done, /* done */
+ ZERO_NULL, /* do_more */
+ rtsp_connect, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ rtsp_getsock_do, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ rtsp_disconnect, /* disconnect */
+ rtsp_rtp_readwrite, /* readwrite */
+ PORT_RTSP, /* defport */
+ CURLPROTO_RTSP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+
+static CURLcode rtsp_setup_connection(struct connectdata *conn)
+{
+ struct RTSP *rtsp;
+
+ conn->data->req.protop = rtsp = calloc(1, sizeof(struct RTSP));
+ if(!rtsp)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+
+/*
+ * The server may send us RTP data at any point, and RTSPREQ_RECEIVE does not
+ * want to block the application forever while receiving a stream. Therefore,
+ * we cannot assume that an RTSP socket is dead just because it is readable.
+ *
+ * Instead, if it is readable, run Curl_getconnectinfo() to peek at the socket
+ * and distinguish between closed and data.
+ */
+bool Curl_rtsp_connisdead(struct connectdata *check)
+{
+ int sval;
+ bool ret_val = TRUE;
+
+ sval = Curl_socket_ready(check->sock[FIRSTSOCKET], CURL_SOCKET_BAD, 0);
+ if(sval == 0) {
+ /* timeout */
+ ret_val = FALSE;
+ }
+ else if(sval & CURL_CSELECT_ERR) {
+ /* socket is in an error state */
+ ret_val = TRUE;
+ }
+ else if((sval & CURL_CSELECT_IN) && check->data) {
+ /* readable with no error. could be closed or could be alive but we can
+ only check if we have a proper SessionHandle for the connection */
+ curl_socket_t connectinfo = Curl_getconnectinfo(check->data, &check);
+ if(connectinfo != CURL_SOCKET_BAD)
+ ret_val = FALSE;
+ }
+
+ return ret_val;
+}
+
+static CURLcode rtsp_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode httpStatus;
+ struct SessionHandle *data = conn->data;
+
+ httpStatus = Curl_http_connect(conn, done);
+
+ /* Initialize the CSeq if not already done */
+ if(data->state.rtsp_next_client_CSeq == 0)
+ data->state.rtsp_next_client_CSeq = 1;
+ if(data->state.rtsp_next_server_CSeq == 0)
+ data->state.rtsp_next_server_CSeq = 1;
+
+ conn->proto.rtspc.rtp_channel = -1;
+
+ return httpStatus;
+}
+
+static CURLcode rtsp_disconnect(struct connectdata *conn, bool dead)
+{
+ (void) dead;
+ Curl_safefree(conn->proto.rtspc.rtp_buf);
+ return CURLE_OK;
+}
+
+
+static CURLcode rtsp_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct SessionHandle *data = conn->data;
+ struct RTSP *rtsp = data->req.protop;
+ CURLcode httpStatus;
+ long CSeq_sent;
+ long CSeq_recv;
+
+ /* Bypass HTTP empty-reply checks on receive */
+ if(data->set.rtspreq == RTSPREQ_RECEIVE)
+ premature = TRUE;
+
+ httpStatus = Curl_http_done(conn, status, premature);
+
+ if(rtsp) {
+ /* Check the sequence numbers */
+ CSeq_sent = rtsp->CSeq_sent;
+ CSeq_recv = rtsp->CSeq_recv;
+ if((data->set.rtspreq != RTSPREQ_RECEIVE) && (CSeq_sent != CSeq_recv)) {
+ failf(data,
+ "The CSeq of this request %ld did not match the response %ld",
+ CSeq_sent, CSeq_recv);
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ else if(data->set.rtspreq == RTSPREQ_RECEIVE &&
+ (conn->proto.rtspc.rtp_channel == -1)) {
+ infof(data, "Got an RTP Receive with a CSeq of %ld\n", CSeq_recv);
+ /* TODO CPC: Server -> Client logic here */
+ }
+ }
+
+ return httpStatus;
+}
+
+static CURLcode rtsp_do(struct connectdata *conn, bool *done)
+{
+ struct SessionHandle *data = conn->data;
+ CURLcode result=CURLE_OK;
+ Curl_RtspReq rtspreq = data->set.rtspreq;
+ struct RTSP *rtsp = data->req.protop;
+ struct HTTP *http;
+ Curl_send_buffer *req_buffer;
+ curl_off_t postsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+ curl_off_t putsize = 0; /* for ANNOUNCE and SET_PARAMETER */
+
+ const char *p_request = NULL;
+ const char *p_session_id = NULL;
+ const char *p_accept = NULL;
+ const char *p_accept_encoding = NULL;
+ const char *p_range = NULL;
+ const char *p_referrer = NULL;
+ const char *p_stream_uri = NULL;
+ const char *p_transport = NULL;
+ const char *p_uagent = NULL;
+
+ *done = TRUE;
+
+ http = &(rtsp->http_wrapper);
+ /* Assert that no one has changed the RTSP struct in an evil way */
+ DEBUGASSERT((void *)http == (void *)rtsp);
+
+ rtsp->CSeq_sent = data->state.rtsp_next_client_CSeq;
+ rtsp->CSeq_recv = 0;
+
+ /* Setup the 'p_request' pointer to the proper p_request string
+ * Since all RTSP requests are included here, there is no need to
+ * support custom requests like HTTP.
+ **/
+ DEBUGASSERT((rtspreq > RTSPREQ_NONE && rtspreq < RTSPREQ_LAST));
+ data->set.opt_no_body = TRUE; /* most requests don't contain a body */
+ switch(rtspreq) {
+ case RTSPREQ_NONE:
+ failf(data, "Got invalid RTSP request: RTSPREQ_NONE");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ case RTSPREQ_OPTIONS:
+ p_request = "OPTIONS";
+ break;
+ case RTSPREQ_DESCRIBE:
+ p_request = "DESCRIBE";
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_ANNOUNCE:
+ p_request = "ANNOUNCE";
+ break;
+ case RTSPREQ_SETUP:
+ p_request = "SETUP";
+ break;
+ case RTSPREQ_PLAY:
+ p_request = "PLAY";
+ break;
+ case RTSPREQ_PAUSE:
+ p_request = "PAUSE";
+ break;
+ case RTSPREQ_TEARDOWN:
+ p_request = "TEARDOWN";
+ break;
+ case RTSPREQ_GET_PARAMETER:
+ /* GET_PARAMETER's no_body status is determined later */
+ p_request = "GET_PARAMETER";
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_SET_PARAMETER:
+ p_request = "SET_PARAMETER";
+ break;
+ case RTSPREQ_RECORD:
+ p_request = "RECORD";
+ break;
+ case RTSPREQ_RECEIVE:
+ p_request = "";
+ /* Treat interleaved RTP as body*/
+ data->set.opt_no_body = FALSE;
+ break;
+ case RTSPREQ_LAST:
+ failf(data, "Got invalid RTSP request: RTSPREQ_LAST");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ if(rtspreq == RTSPREQ_RECEIVE) {
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE,
+ &http->readbytecount, -1, NULL);
+
+ return result;
+ }
+
+ p_session_id = data->set.str[STRING_RTSP_SESSION_ID];
+ if(!p_session_id &&
+ (rtspreq & ~(RTSPREQ_OPTIONS | RTSPREQ_DESCRIBE | RTSPREQ_SETUP))) {
+ failf(data, "Refusing to issue an RTSP request [%s] without a session ID.",
+ p_request ? p_request : "");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ /* TODO: auth? */
+ /* TODO: proxy? */
+
+ /* Stream URI. Default to server '*' if not specified */
+ if(data->set.str[STRING_RTSP_STREAM_URI]) {
+ p_stream_uri = data->set.str[STRING_RTSP_STREAM_URI];
+ }
+ else {
+ p_stream_uri = "*";
+ }
+
+ /* Transport Header for SETUP requests */
+ p_transport = Curl_checkheaders(data, "Transport:");
+ if(rtspreq == RTSPREQ_SETUP && !p_transport) {
+ /* New Transport: setting? */
+ if(data->set.str[STRING_RTSP_TRANSPORT]) {
+ Curl_safefree(conn->allocptr.rtsp_transport);
+
+ conn->allocptr.rtsp_transport =
+ aprintf("Transport: %s\r\n",
+ data->set.str[STRING_RTSP_TRANSPORT]);
+ if(!conn->allocptr.rtsp_transport)
+ return CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ failf(data,
+ "Refusing to issue an RTSP SETUP without a Transport: header.");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ p_transport = conn->allocptr.rtsp_transport;
+ }
+
+ /* Accept Headers for DESCRIBE requests */
+ if(rtspreq == RTSPREQ_DESCRIBE) {
+ /* Accept Header */
+ p_accept = Curl_checkheaders(data, "Accept:")?
+ NULL:"Accept: application/sdp\r\n";
+
+ /* Accept-Encoding header */
+ if(!Curl_checkheaders(data, "Accept-Encoding:") &&
+ data->set.str[STRING_ENCODING]) {
+ Curl_safefree(conn->allocptr.accept_encoding);
+ conn->allocptr.accept_encoding =
+ aprintf("Accept-Encoding: %s\r\n", data->set.str[STRING_ENCODING]);
+
+ if(!conn->allocptr.accept_encoding)
+ return CURLE_OUT_OF_MEMORY;
+
+ p_accept_encoding = conn->allocptr.accept_encoding;
+ }
+ }
+
+ /* The User-Agent string might have been allocated in url.c already, because
+ it might have been used in the proxy connect, but if we have got a header
+ with the user-agent string specified, we erase the previously made string
+ here. */
+ if(Curl_checkheaders(data, "User-Agent:") && conn->allocptr.uagent) {
+ Curl_safefree(conn->allocptr.uagent);
+ conn->allocptr.uagent = NULL;
+ }
+ else if(!Curl_checkheaders(data, "User-Agent:") &&
+ data->set.str[STRING_USERAGENT]) {
+ p_uagent = conn->allocptr.uagent;
+ }
+
+ /* Referrer */
+ Curl_safefree(conn->allocptr.ref);
+ if(data->change.referer && !Curl_checkheaders(data, "Referer:"))
+ conn->allocptr.ref = aprintf("Referer: %s\r\n", data->change.referer);
+ else
+ conn->allocptr.ref = NULL;
+
+ p_referrer = conn->allocptr.ref;
+
+ /*
+ * Range Header
+ * Only applies to PLAY, PAUSE, RECORD
+ *
+ * Go ahead and use the Range stuff supplied for HTTP
+ */
+ if(data->state.use_range &&
+ (rtspreq & (RTSPREQ_PLAY | RTSPREQ_PAUSE | RTSPREQ_RECORD))) {
+
+ /* Check to see if there is a range set in the custom headers */
+ if(!Curl_checkheaders(data, "Range:") && data->state.range) {
+ Curl_safefree(conn->allocptr.rangeline);
+ conn->allocptr.rangeline = aprintf("Range: %s\r\n", data->state.range);
+ p_range = conn->allocptr.rangeline;
+ }
+ }
+
+ /*
+ * Sanity check the custom headers
+ */
+ if(Curl_checkheaders(data, "CSeq:")) {
+ failf(data, "CSeq cannot be set as a custom header.");
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ if(Curl_checkheaders(data, "Session:")) {
+ failf(data, "Session ID cannot be set as a custom header.");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ /* Initialize a dynamic send buffer */
+ req_buffer = Curl_add_buffer_init();
+
+ if(!req_buffer)
+ return CURLE_OUT_OF_MEMORY;
+
+ result =
+ Curl_add_bufferf(req_buffer,
+ "%s %s RTSP/1.0\r\n" /* Request Stream-URI RTSP/1.0 */
+ "CSeq: %ld\r\n", /* CSeq */
+ (p_request ? p_request : ""), p_stream_uri,
+ rtsp->CSeq_sent);
+ if(result)
+ return result;
+
+ /*
+ * Rather than do a normal alloc line, keep the session_id unformatted
+ * to make comparison easier
+ */
+ if(p_session_id) {
+ result = Curl_add_bufferf(req_buffer, "Session: %s\r\n", p_session_id);
+ if(result)
+ return result;
+ }
+
+ /*
+ * Shared HTTP-like options
+ */
+ result = Curl_add_bufferf(req_buffer,
+ "%s" /* transport */
+ "%s" /* accept */
+ "%s" /* accept-encoding */
+ "%s" /* range */
+ "%s" /* referrer */
+ "%s" /* user-agent */
+ ,
+ p_transport ? p_transport : "",
+ p_accept ? p_accept : "",
+ p_accept_encoding ? p_accept_encoding : "",
+ p_range ? p_range : "",
+ p_referrer ? p_referrer : "",
+ p_uagent ? p_uagent : "");
+ if(result)
+ return result;
+
+ if((rtspreq == RTSPREQ_SETUP) || (rtspreq == RTSPREQ_DESCRIBE)) {
+ result = Curl_add_timecondition(data, req_buffer);
+ if(result)
+ return result;
+ }
+
+ result = Curl_add_custom_headers(conn, req_buffer);
+ if(result)
+ return result;
+
+ if(rtspreq == RTSPREQ_ANNOUNCE ||
+ rtspreq == RTSPREQ_SET_PARAMETER ||
+ rtspreq == RTSPREQ_GET_PARAMETER) {
+
+ if(data->set.upload) {
+ putsize = data->set.infilesize;
+ data->set.httpreq = HTTPREQ_PUT;
+
+ }
+ else {
+ postsize = (data->set.postfieldsize != -1)?
+ data->set.postfieldsize:
+ (data->set.postfields? (curl_off_t)strlen(data->set.postfields):0);
+ data->set.httpreq = HTTPREQ_POST;
+ }
+
+ if(putsize > 0 || postsize > 0) {
+ /* As stated in the http comments, it is probably not wise to
+ * actually set a custom Content-Length in the headers */
+ if(!Curl_checkheaders(data, "Content-Length:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Length: %" FORMAT_OFF_T"\r\n",
+ (data->set.upload ? putsize : postsize));
+ if(result)
+ return result;
+ }
+
+ if(rtspreq == RTSPREQ_SET_PARAMETER ||
+ rtspreq == RTSPREQ_GET_PARAMETER) {
+ if(!Curl_checkheaders(data, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: text/parameters\r\n");
+ if(result)
+ return result;
+ }
+ }
+
+ if(rtspreq == RTSPREQ_ANNOUNCE) {
+ if(!Curl_checkheaders(data, "Content-Type:")) {
+ result = Curl_add_bufferf(req_buffer,
+ "Content-Type: application/sdp\r\n");
+ if(result)
+ return result;
+ }
+ }
+
+ data->state.expect100header = FALSE; /* RTSP posts are simple/small */
+ }
+ else if(rtspreq == RTSPREQ_GET_PARAMETER) {
+ /* Check for an empty GET_PARAMETER (heartbeat) request */
+ data->set.httpreq = HTTPREQ_HEAD;
+ data->set.opt_no_body = TRUE;
+ }
+ }
+
+ /* RTSP never allows chunked transfer */
+ data->req.forbidchunk = TRUE;
+ /* Finish the request buffer */
+ result = Curl_add_buffer(req_buffer, "\r\n", 2);
+ if(result)
+ return result;
+
+ if(postsize > 0) {
+ result = Curl_add_buffer(req_buffer, data->set.postfields,
+ (size_t)postsize);
+ if(result)
+ return result;
+ }
+
+ /* issue the request */
+ result = Curl_add_buffer_send(req_buffer, conn,
+ &data->info.request_size, 0, FIRSTSOCKET);
+ if(result) {
+ failf(data, "Failed sending RTSP request");
+ return result;
+ }
+
+ Curl_setup_transfer(conn, FIRSTSOCKET, -1, TRUE, &http->readbytecount,
+ putsize?FIRSTSOCKET:-1,
+ putsize?&http->writebytecount:NULL);
+
+ /* Increment the CSeq on success */
+ data->state.rtsp_next_client_CSeq++;
+
+ if(http->writebytecount) {
+ /* if a request-body has been sent off, we make sure this progress is
+ noted properly */
+ Curl_pgrsSetUploadCounter(data, http->writebytecount);
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ }
+
+ return result;
+}
+
+
+static CURLcode rtsp_rtp_readwrite(struct SessionHandle *data,
+ struct connectdata *conn,
+ ssize_t *nread,
+ bool *readmore) {
+ struct SingleRequest *k = &data->req;
+ struct rtsp_conn *rtspc = &(conn->proto.rtspc);
+
+ char *rtp; /* moving pointer to rtp data */
+ ssize_t rtp_dataleft; /* how much data left to parse in this round */
+ char *scratch;
+ CURLcode result;
+
+ if(rtspc->rtp_buf) {
+ /* There was some leftover data the last time. Merge buffers */
+ char *newptr = realloc(rtspc->rtp_buf, rtspc->rtp_bufsize + *nread);
+ if(!newptr) {
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ rtspc->rtp_buf = newptr;
+ memcpy(rtspc->rtp_buf + rtspc->rtp_bufsize, k->str, *nread);
+ rtspc->rtp_bufsize += *nread;
+ rtp = rtspc->rtp_buf;
+ rtp_dataleft = rtspc->rtp_bufsize;
+ }
+ else {
+ /* Just parse the request buffer directly */
+ rtp = k->str;
+ rtp_dataleft = *nread;
+ }
+
+ while((rtp_dataleft > 0) &&
+ (rtp[0] == '$')) {
+ if(rtp_dataleft > 4) {
+ int rtp_length;
+
+ /* Parse the header */
+ /* The channel identifier immediately follows and is 1 byte */
+ rtspc->rtp_channel = RTP_PKT_CHANNEL(rtp);
+
+ /* The length is two bytes */
+ rtp_length = RTP_PKT_LENGTH(rtp);
+
+ if(rtp_dataleft < rtp_length + 4) {
+ /* Need more - incomplete payload*/
+ *readmore = TRUE;
+ break;
+ }
+ else {
+ /* We have the full RTP interleaved packet
+ * Write out the header including the leading '$' */
+ DEBUGF(infof(data, "RTP write channel %d rtp_length %d\n",
+ rtspc->rtp_channel, rtp_length));
+ result = rtp_client_write(conn, &rtp[0], rtp_length + 4);
+ if(result) {
+ failf(data, "Got an error writing an RTP packet");
+ *readmore = FALSE;
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return result;
+ }
+
+ /* Move forward in the buffer */
+ rtp_dataleft -= rtp_length + 4;
+ rtp += rtp_length + 4;
+
+ if(data->set.rtspreq == RTSPREQ_RECEIVE) {
+ /* If we are in a passive receive, give control back
+ * to the app as often as we can.
+ */
+ k->keepon &= ~KEEP_RECV;
+ }
+ }
+ }
+ else {
+ /* Need more - incomplete header */
+ *readmore = TRUE;
+ break;
+ }
+ }
+
+ if(rtp_dataleft != 0 && rtp[0] == '$') {
+ DEBUGF(infof(data, "RTP Rewinding %zd %s\n", rtp_dataleft,
+ *readmore ? "(READMORE)" : ""));
+
+ /* Store the incomplete RTP packet for a "rewind" */
+ scratch = malloc(rtp_dataleft);
+ if(!scratch) {
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(scratch, rtp, rtp_dataleft);
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = scratch;
+ rtspc->rtp_bufsize = rtp_dataleft;
+
+ /* As far as the transfer is concerned, this data is consumed */
+ *nread = 0;
+ return CURLE_OK;
+ }
+ else {
+ /* Fix up k->str to point just after the last RTP packet */
+ k->str += *nread - rtp_dataleft;
+
+ /* either all of the data has been read or...
+ * rtp now points at the next byte to parse
+ */
+ if(rtp_dataleft > 0)
+ DEBUGASSERT(k->str[0] == rtp[0]);
+
+ DEBUGASSERT(rtp_dataleft <= *nread); /* sanity check */
+
+ *nread = rtp_dataleft;
+ }
+
+ /* If we get here, we have finished with the leftover/merge buffer */
+ Curl_safefree(rtspc->rtp_buf);
+ rtspc->rtp_buf = NULL;
+ rtspc->rtp_bufsize = 0;
+
+ return CURLE_OK;
+}
+
+static
+CURLcode rtp_client_write(struct connectdata *conn, char *ptr, size_t len)
+{
+ struct SessionHandle *data = conn->data;
+ size_t wrote;
+ curl_write_callback writeit;
+
+ if(len == 0) {
+ failf (data, "Cannot write a 0 size RTP packet.");
+ return CURLE_WRITE_ERROR;
+ }
+
+ writeit = data->set.fwrite_rtp?data->set.fwrite_rtp:data->set.fwrite_func;
+ wrote = writeit(ptr, 1, len, data->set.rtp_out);
+
+ if(CURL_WRITEFUNC_PAUSE == wrote) {
+ failf (data, "Cannot pause RTP");
+ return CURLE_WRITE_ERROR;
+ }
+
+ if(wrote != len) {
+ failf (data, "Failed writing RTP data");
+ return CURLE_WRITE_ERROR;
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn,
+ char *header)
+{
+ struct SessionHandle *data = conn->data;
+ long CSeq = 0;
+
+ if(checkprefix("CSeq:", header)) {
+ /* Store the received CSeq. Match is verified in rtsp_done */
+ int nc = sscanf(&header[4], ": %ld", &CSeq);
+ if(nc == 1) {
+ struct RTSP *rtsp = data->req.protop;
+ rtsp->CSeq_recv = CSeq; /* mark the request */
+ data->state.rtsp_CSeq_recv = CSeq; /* update the handle */
+ }
+ else {
+ failf(data, "Unable to read the CSeq header: [%s]", header);
+ return CURLE_RTSP_CSEQ_ERROR;
+ }
+ }
+ else if(checkprefix("Session:", header)) {
+ char *start;
+
+ /* Find the first non-space letter */
+ start = header + 9;
+ while(*start && ISSPACE(*start))
+ start++;
+
+ if(!*start) {
+ failf(data, "Got a blank Session ID");
+ }
+ else if(data->set.str[STRING_RTSP_SESSION_ID]) {
+ /* If the Session ID is set, then compare */
+ if(strncmp(start, data->set.str[STRING_RTSP_SESSION_ID],
+ strlen(data->set.str[STRING_RTSP_SESSION_ID])) != 0) {
+ failf(data, "Got RTSP Session ID Line [%s], but wanted ID [%s]",
+ start, data->set.str[STRING_RTSP_SESSION_ID]);
+ return CURLE_RTSP_SESSION_ERROR;
+ }
+ }
+ else {
+ /* If the Session ID is not set, and we find it in a response, then
+ set it */
+
+ /* The session ID can be an alphanumeric or a 'safe' character
+ *
+ * RFC 2326 15.1 Base Syntax:
+ * safe = "\$" | "-" | "_" | "." | "+"
+ * */
+ char *end = start;
+ while(*end &&
+ (ISALNUM(*end) || *end == '-' || *end == '_' || *end == '.' ||
+ *end == '+' ||
+ (*end == '\\' && *(end + 1) && *(end + 1) == '$' && (++end, 1))))
+ end++;
+
+ /* Copy the id substring into a new buffer */
+ data->set.str[STRING_RTSP_SESSION_ID] = malloc(end - start + 1);
+ if(data->set.str[STRING_RTSP_SESSION_ID] == NULL)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(data->set.str[STRING_RTSP_SESSION_ID], start, end - start);
+ (data->set.str[STRING_RTSP_SESSION_ID])[end - start] = '\0';
+ }
+ }
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_RTSP */
diff --git a/libs/libcurl/src/rtsp.h b/libs/libcurl/src/rtsp.h
new file mode 100644
index 0000000000..3ffa70cc6c
--- /dev/null
+++ b/libs/libcurl/src/rtsp.h
@@ -0,0 +1,69 @@
+#ifndef HEADER_CURL_RTSP_H
+#define HEADER_CURL_RTSP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_RTSP
+
+extern const struct Curl_handler Curl_handler_rtsp;
+
+bool Curl_rtsp_connisdead(struct connectdata *check);
+CURLcode Curl_rtsp_parseheader(struct connectdata *conn, char *header);
+
+#else
+/* disabled */
+#define Curl_rtsp_parseheader(x,y) CURLE_NOT_BUILT_IN
+#define Curl_rtsp_connisdead(x) TRUE
+
+#endif /* CURL_DISABLE_RTSP */
+
+/*
+ * RTSP Connection data
+ *
+ * Currently, only used for tracking incomplete RTP data reads
+ */
+struct rtsp_conn {
+ char *rtp_buf;
+ ssize_t rtp_bufsize;
+ int rtp_channel;
+};
+
+/****************************************************************************
+ * RTSP unique setup
+ ***************************************************************************/
+struct RTSP {
+ /*
+ * http_wrapper MUST be the first element of this structure for the wrap
+ * logic to work. In this way, we get a cheap polymorphism because
+ * &(data->state.proto.rtsp) == &(data->state.proto.http) per the C spec
+ *
+ * HTTP functions can safely treat this as an HTTP struct, but RTSP aware
+ * functions can also index into the later elements.
+ */
+ struct HTTP http_wrapper; /*wrap HTTP to do the heavy lifting */
+
+ long CSeq_sent; /* CSeq of this request */
+ long CSeq_recv; /* CSeq received */
+};
+
+
+#endif /* HEADER_CURL_RTSP_H */
+
diff --git a/libs/libcurl/src/security.c b/libs/libcurl/src/security.c
new file mode 100644
index 0000000000..fa05207617
--- /dev/null
+++ b/libs/libcurl/src/security.c
@@ -0,0 +1,601 @@
+/* This source code was modified by Martin Hedenfalk <mhe@stacken.kth.se> for
+ * use in Curl. His latest changes were done 2000-09-18.
+ *
+ * It has since been patched and modified a lot by Daniel Stenberg
+ * <daniel@haxx.se> to make it better applied to curl conditions, and to make
+ * it not use globals, pollute name space and more. This source code awaits a
+ * rewrite to work around the paragraph 2 in the BSD licenses as explained
+ * below.
+ *
+ * Copyright (c) 1998, 1999, 2013 Kungliga Tekniska Hgskolan
+ * (Royal Institute of Technology, Stockholm, Sweden).
+ *
+ * Copyright (C) 2001 - 2013, Daniel Stenberg, <daniel@haxx.se>, et al.
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the Institute nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE. */
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_FTP
+#ifdef HAVE_GSSAPI
+
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "curl_base64.h"
+#include "curl_memory.h"
+#include "curl_sec.h"
+#include "ftp.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "warnless.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+static const struct {
+ enum protection_level level;
+ const char *name;
+} level_names[] = {
+ { PROT_CLEAR, "clear" },
+ { PROT_SAFE, "safe" },
+ { PROT_CONFIDENTIAL, "confidential" },
+ { PROT_PRIVATE, "private" }
+};
+
+static enum protection_level
+name_to_level(const char *name)
+{
+ int i;
+ for(i = 0; i < sizeof(level_names)/sizeof(level_names[0]); i++)
+ if(checkprefix(name, level_names[i].name))
+ return level_names[i].level;
+ return PROT_NONE;
+}
+
+/* Convert a protocol |level| to its char representation.
+ We take an int to catch programming mistakes. */
+static char level_to_char(int level) {
+ switch(level) {
+ case PROT_CLEAR:
+ return 'C';
+ case PROT_SAFE:
+ return 'S';
+ case PROT_CONFIDENTIAL:
+ return 'E';
+ case PROT_PRIVATE:
+ return 'P';
+ case PROT_CMD:
+ /* Fall through */
+ default:
+ /* Those 2 cases should not be reached! */
+ break;
+ }
+ DEBUGASSERT(0);
+ /* Default to the most secure alternative. */
+ return 'P';
+}
+
+static const struct Curl_sec_client_mech * const mechs[] = {
+#ifdef HAVE_GSSAPI
+ &Curl_krb5_client_mech,
+#endif
+ NULL
+};
+
+/* Send an FTP command defined by |message| and the optional arguments. The
+ function returns the ftp_code. If an error occurs, -1 is returned. */
+static int ftp_send_command(struct connectdata *conn, const char *message, ...)
+{
+ int ftp_code;
+ ssize_t nread;
+ va_list args;
+ char print_buffer[50];
+
+ va_start(args, message);
+ vsnprintf(print_buffer, sizeof(print_buffer), message, args);
+ va_end(args);
+
+ if(Curl_ftpsendf(conn, print_buffer) != CURLE_OK) {
+ ftp_code = -1;
+ }
+ else {
+ if(Curl_GetFTPResponse(&nread, conn, &ftp_code) != CURLE_OK)
+ ftp_code = -1;
+ }
+
+ (void)nread; /* Unused */
+ return ftp_code;
+}
+
+/* Read |len| from the socket |fd| and store it in |to|. Return a CURLcode
+ saying whether an error occurred or CURLE_OK if |len| was read. */
+static CURLcode
+socket_read(curl_socket_t fd, void *to, size_t len)
+{
+ char *to_p = to;
+ CURLcode code;
+ ssize_t nread;
+
+ while(len > 0) {
+ code = Curl_read_plain(fd, to_p, len, &nread);
+ if(code == CURLE_OK) {
+ len -= nread;
+ to_p += nread;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(code == CURLE_AGAIN)
+ continue;
+ return code;
+ }
+ }
+ return CURLE_OK;
+}
+
+
+/* Write |len| bytes from the buffer |to| to the socket |fd|. Return a
+ CURLcode saying whether an error occurred or CURLE_OK if |len| was
+ written. */
+static CURLcode
+socket_write(struct connectdata *conn, curl_socket_t fd, const void *to,
+ size_t len)
+{
+ const char *to_p = to;
+ CURLcode code;
+ ssize_t written;
+
+ while(len > 0) {
+ code = Curl_write_plain(conn, fd, to_p, len, &written);
+ if(code == CURLE_OK) {
+ len -= written;
+ to_p += written;
+ }
+ else {
+ /* FIXME: We are doing a busy wait */
+ if(code == CURLE_AGAIN)
+ continue;
+ return code;
+ }
+ }
+ return CURLE_OK;
+}
+
+static CURLcode read_data(struct connectdata *conn,
+ curl_socket_t fd,
+ struct krb5buffer *buf)
+{
+ int len;
+ void* tmp;
+ CURLcode ret;
+
+ ret = socket_read(fd, &len, sizeof(len));
+ if(ret != CURLE_OK)
+ return ret;
+
+ len = ntohl(len);
+ tmp = realloc(buf->data, len);
+ if(tmp == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ buf->data = tmp;
+ ret = socket_read(fd, buf->data, len);
+ if(ret != CURLE_OK)
+ return ret;
+ buf->size = conn->mech->decode(conn->app_data, buf->data, len,
+ conn->data_prot, conn);
+ buf->index = 0;
+ return CURLE_OK;
+}
+
+static size_t
+buffer_read(struct krb5buffer *buf, void *data, size_t len)
+{
+ if(buf->size - buf->index < len)
+ len = buf->size - buf->index;
+ memcpy(data, (char*)buf->data + buf->index, len);
+ buf->index += len;
+ return len;
+}
+
+/* Matches Curl_recv signature */
+static ssize_t sec_recv(struct connectdata *conn, int sockindex,
+ char *buffer, size_t len, CURLcode *err)
+{
+ size_t bytes_read;
+ size_t total_read = 0;
+ curl_socket_t fd = conn->sock[sockindex];
+
+ *err = CURLE_OK;
+
+ /* Handle clear text response. */
+ if(conn->sec_complete == 0 || conn->data_prot == PROT_CLEAR)
+ return read(fd, buffer, len);
+
+ if(conn->in_buffer.eof_flag) {
+ conn->in_buffer.eof_flag = 0;
+ return 0;
+ }
+
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
+
+ while(len > 0) {
+ if(read_data(conn, fd, &conn->in_buffer) != CURLE_OK)
+ return -1;
+ if(conn->in_buffer.size == 0) {
+ if(bytes_read > 0)
+ conn->in_buffer.eof_flag = 1;
+ return bytes_read;
+ }
+ bytes_read = buffer_read(&conn->in_buffer, buffer, len);
+ len -= bytes_read;
+ total_read += bytes_read;
+ buffer += bytes_read;
+ }
+ /* FIXME: Check for overflow */
+ return total_read;
+}
+
+/* Send |length| bytes from |from| to the |fd| socket taking care of encoding
+ and negociating with the server. |from| can be NULL. */
+/* FIXME: We don't check for errors nor report any! */
+static void do_sec_send(struct connectdata *conn, curl_socket_t fd,
+ const char *from, int length)
+{
+ int bytes, htonl_bytes; /* 32-bit integers for htonl */
+ char *buffer = NULL;
+ char *cmd_buffer;
+ size_t cmd_size = 0;
+ CURLcode error;
+ enum protection_level prot_level = conn->data_prot;
+ bool iscmd = (prot_level == PROT_CMD)?TRUE:FALSE;
+
+ DEBUGASSERT(prot_level > PROT_NONE && prot_level < PROT_LAST);
+
+ if(iscmd) {
+ if(!strncmp(from, "PASS ", 5) || !strncmp(from, "ACCT ", 5))
+ prot_level = PROT_PRIVATE;
+ else
+ prot_level = conn->command_prot;
+ }
+ bytes = conn->mech->encode(conn->app_data, from, length, prot_level,
+ (void**)&buffer, conn);
+ if(!buffer || bytes <= 0)
+ return; /* error */
+
+ if(iscmd) {
+ error = Curl_base64_encode(conn->data, buffer, curlx_sitouz(bytes),
+ &cmd_buffer, &cmd_size);
+ if(error) {
+ free(buffer);
+ return; /* error */
+ }
+ if(cmd_size > 0) {
+ static const char *enc = "ENC ";
+ static const char *mic = "MIC ";
+ if(prot_level == PROT_PRIVATE)
+ socket_write(conn, fd, enc, 4);
+ else
+ socket_write(conn, fd, mic, 4);
+
+ socket_write(conn, fd, cmd_buffer, cmd_size);
+ socket_write(conn, fd, "\r\n", 2);
+ infof(conn->data, "Send: %s%s\n", prot_level == PROT_PRIVATE?enc:mic,
+ cmd_buffer);
+ free(cmd_buffer);
+ }
+ }
+ else {
+ htonl_bytes = htonl(bytes);
+ socket_write(conn, fd, &htonl_bytes, sizeof(htonl_bytes));
+ socket_write(conn, fd, buffer, curlx_sitouz(bytes));
+ }
+ free(buffer);
+}
+
+static ssize_t sec_write(struct connectdata *conn, curl_socket_t fd,
+ const char *buffer, size_t length)
+{
+ /* FIXME: Check for overflow */
+ ssize_t tx = 0, len = conn->buffer_size;
+
+ len -= conn->mech->overhead(conn->app_data, conn->data_prot,
+ curlx_sztosi(len));
+ if(len <= 0)
+ len = length;
+ while(length) {
+ if(len >= 0 || length < (size_t)len) {
+ /* FIXME: Check for overflow. */
+ len = length;
+ }
+ do_sec_send(conn, fd, buffer, curlx_sztosi(len));
+ length -= len;
+ buffer += len;
+ tx += len;
+ }
+ return tx;
+}
+
+/* Matches Curl_send signature */
+static ssize_t sec_send(struct connectdata *conn, int sockindex,
+ const void *buffer, size_t len, CURLcode *err)
+{
+ curl_socket_t fd = conn->sock[sockindex];
+ *err = CURLE_OK;
+ return sec_write(conn, fd, buffer, len);
+}
+
+int Curl_sec_read_msg(struct connectdata *conn, char *buffer,
+ enum protection_level level)
+{
+ /* decoded_len should be size_t or ssize_t but conn->mech->decode returns an
+ int */
+ int decoded_len;
+ char *buf;
+ int ret_code;
+ size_t decoded_sz = 0;
+ CURLcode error;
+
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+ error = Curl_base64_decode(buffer + 4, (unsigned char **)&buf, &decoded_sz);
+ if(error || decoded_sz == 0)
+ return -1;
+
+ if(decoded_sz > (size_t)INT_MAX) {
+ free(buf);
+ return -1;
+ }
+ decoded_len = curlx_uztosi(decoded_sz);
+
+ decoded_len = conn->mech->decode(conn->app_data, buf, decoded_len,
+ level, conn);
+ if(decoded_len <= 0) {
+ free(buf);
+ return -1;
+ }
+
+ if(conn->data->set.verbose) {
+ buf[decoded_len] = '\n';
+ Curl_debug(conn->data, CURLINFO_HEADER_IN, buf, decoded_len + 1, conn);
+ }
+
+ buf[decoded_len] = '\0';
+ DEBUGASSERT(decoded_len > 3);
+ if(buf[3] == '-')
+ ret_code = 0;
+ else {
+ /* Check for error? */
+ sscanf(buf, "%d", &ret_code);
+ }
+
+ if(buf[decoded_len - 1] == '\n')
+ buf[decoded_len - 1] = '\0';
+ /* FIXME: Is |buffer| length always greater than |decoded_len|? */
+ strcpy(buffer, buf);
+ free(buf);
+ return ret_code;
+}
+
+/* FIXME: The error code returned here is never checked. */
+static int sec_set_protection_level(struct connectdata *conn)
+{
+ int code;
+ char* pbsz;
+ static unsigned int buffer_size = 1 << 20; /* 1048576 */
+ enum protection_level level = conn->request_data_prot;
+
+ DEBUGASSERT(level > PROT_NONE && level < PROT_LAST);
+
+ if(!conn->sec_complete) {
+ infof(conn->data, "Trying to change the protection level after the"
+ "completion of the data exchange.\n");
+ return -1;
+ }
+
+ /* Bail out if we try to set up the same level */
+ if(conn->data_prot == level)
+ return 0;
+
+ if(level) {
+ code = ftp_send_command(conn, "PBSZ %u", buffer_size);
+ if(code < 0)
+ return -1;
+
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection's buffer size.");
+ return -1;
+ }
+ conn->buffer_size = buffer_size;
+
+ pbsz = strstr(conn->data->state.buffer, "PBSZ=");
+ if(pbsz) {
+ /* FIXME: Checks for errors in sscanf? */
+ sscanf(pbsz, "PBSZ=%u", &buffer_size);
+ if(buffer_size < conn->buffer_size)
+ conn->buffer_size = buffer_size;
+ }
+ }
+
+ /* Now try to negiociate the protection level. */
+ code = ftp_send_command(conn, "PROT %c", level_to_char(level));
+
+ if(code < 0)
+ return -1;
+
+ if(code/100 != 2) {
+ failf(conn->data, "Failed to set the protection level.");
+ return -1;
+ }
+
+ conn->data_prot = level;
+ if(level == PROT_PRIVATE)
+ conn->command_prot = level;
+
+ return 0;
+}
+
+int
+Curl_sec_request_prot(struct connectdata *conn, const char *level)
+{
+ enum protection_level l = name_to_level(level);
+ if(l == PROT_NONE)
+ return -1;
+ DEBUGASSERT(l > PROT_NONE && l < PROT_LAST);
+ conn->request_data_prot = l;
+ return 0;
+}
+
+static CURLcode choose_mech(struct connectdata *conn)
+{
+ int ret;
+ struct SessionHandle *data = conn->data;
+ const struct Curl_sec_client_mech * const *mech;
+ void *tmp_allocation;
+ const char *mech_name;
+
+ for(mech = mechs; (*mech); ++mech) {
+ mech_name = (*mech)->name;
+ /* We have no mechanism with a NULL name but keep this check */
+ DEBUGASSERT(mech_name != NULL);
+ if(mech_name == NULL) {
+ infof(data, "Skipping mechanism with empty name (%p)\n", (void *)mech);
+ continue;
+ }
+ tmp_allocation = realloc(conn->app_data, (*mech)->size);
+ if(tmp_allocation == NULL) {
+ failf(data, "Failed realloc of size %u", (*mech)->size);
+ mech = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ conn->app_data = tmp_allocation;
+
+ if((*mech)->init) {
+ ret = (*mech)->init(conn->app_data);
+ if(ret != 0) {
+ infof(data, "Failed initialization for %s. Skipping it.\n", mech_name);
+ continue;
+ }
+ }
+
+ infof(data, "Trying mechanism %s...\n", mech_name);
+ ret = ftp_send_command(conn, "AUTH %s", mech_name);
+ if(ret < 0)
+ /* FIXME: This error is too generic but it is OK for now. */
+ return CURLE_COULDNT_CONNECT;
+
+ if(ret/100 != 3) {
+ switch(ret) {
+ case 504:
+ infof(data, "Mechanism %s is not supported by the server (server "
+ "returned ftp code: 504).\n", mech_name);
+ break;
+ case 534:
+ infof(data, "Mechanism %s was rejected by the server (server returned "
+ "ftp code: 534).\n", mech_name);
+ break;
+ default:
+ if(ret/100 == 5) {
+ infof(data, "server does not support the security extensions\n");
+ return CURLE_USE_SSL_FAILED;
+ }
+ break;
+ }
+ continue;
+ }
+
+ /* Authenticate */
+ ret = (*mech)->auth(conn->app_data, conn);
+
+ if(ret == AUTH_CONTINUE)
+ continue;
+ else if(ret != AUTH_OK) {
+ /* Mechanism has dumped the error to stderr, don't error here. */
+ return -1;
+ }
+ DEBUGASSERT(ret == AUTH_OK);
+
+ conn->mech = *mech;
+ conn->sec_complete = 1;
+ conn->recv[FIRSTSOCKET] = sec_recv;
+ conn->send[FIRSTSOCKET] = sec_send;
+ conn->recv[SECONDARYSOCKET] = sec_recv;
+ conn->send[SECONDARYSOCKET] = sec_send;
+ conn->command_prot = PROT_SAFE;
+ /* Set the requested protection level */
+ /* BLOCKING */
+ (void)sec_set_protection_level(conn);
+ break;
+ }
+
+ return mech != NULL ? CURLE_OK : CURLE_FAILED_INIT;
+}
+
+CURLcode
+Curl_sec_login(struct connectdata *conn)
+{
+ return choose_mech(conn);
+}
+
+
+void
+Curl_sec_end(struct connectdata *conn)
+{
+ if(conn->mech != NULL && conn->mech->end)
+ conn->mech->end(conn->app_data);
+ if(conn->app_data) {
+ free(conn->app_data);
+ conn->app_data = NULL;
+ }
+ if(conn->in_buffer.data) {
+ free(conn->in_buffer.data);
+ conn->in_buffer.data = NULL;
+ conn->in_buffer.size = 0;
+ conn->in_buffer.index = 0;
+ /* FIXME: Is this really needed? */
+ conn->in_buffer.eof_flag = 0;
+ }
+ conn->sec_complete = 0;
+ conn->data_prot = PROT_CLEAR;
+ conn->mech = NULL;
+}
+
+#endif /* HAVE_GSSAPI */
+
+#endif /* CURL_DISABLE_FTP */
diff --git a/libs/libcurl/src/select.c b/libs/libcurl/src/select.c
new file mode 100644
index 0000000000..db7fb6d43c
--- /dev/null
+++ b/libs/libcurl/src/select.c
@@ -0,0 +1,516 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#if !defined(HAVE_SELECT) && !defined(HAVE_POLL_FINE)
+#error "We can't compile without select() or poll() support."
+#endif
+
+#if defined(__BEOS__) && !defined(__HAIKU__)
+/* BeOS has FD_SET defined in socket.h */
+#include <socket.h>
+#endif
+
+#ifdef MSDOS
+#include <dos.h> /* delay() */
+#endif
+
+#include <curl/curl.h>
+
+#include "urldata.h"
+#include "connect.h"
+#include "select.h"
+#include "warnless.h"
+
+/* Convenience local macros */
+
+#define elapsed_ms (int)curlx_tvdiff(curlx_tvnow(), initial_tv)
+
+int Curl_ack_eintr = 0;
+#define error_not_EINTR (Curl_ack_eintr || error != EINTR)
+
+/*
+ * Internal function used for waiting a specific amount of ms
+ * in Curl_socket_ready() and Curl_poll() when no file descriptor
+ * is provided to wait on, just being used to delay execution.
+ * WinSock select() and poll() timeout mechanisms need a valid
+ * socket descriptor in a not null file descriptor set to work.
+ * Waiting indefinitely with this function is not allowed, a
+ * zero or negative timeout value will return immediately.
+ * Timeout resolution, accuracy, as well as maximum supported
+ * value is system dependent, neither factor is a citical issue
+ * for the intended use of this function in the library.
+ *
+ * Return values:
+ * -1 = system call error, invalid timeout value, or interrupted
+ * 0 = specified timeout has elapsed
+ */
+int Curl_wait_ms(int timeout_ms)
+{
+#if !defined(MSDOS) && !defined(USE_WINSOCK)
+#ifndef HAVE_POLL_FINE
+ struct timeval pending_tv;
+#endif
+ struct timeval initial_tv;
+ int pending_ms;
+ int error;
+#endif
+ int r = 0;
+
+ if(!timeout_ms)
+ return 0;
+ if(timeout_ms < 0) {
+ SET_SOCKERRNO(EINVAL);
+ return -1;
+ }
+#if defined(MSDOS)
+ delay(timeout_ms);
+#elif defined(USE_WINSOCK)
+ Sleep(timeout_ms);
+#else
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+ do {
+#if defined(HAVE_POLL_FINE)
+ r = poll(NULL, 0, pending_ms);
+#else
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ r = select(0, NULL, NULL, NULL, &pending_tv);
+#endif /* HAVE_POLL_FINE */
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && error_not_EINTR)
+ break;
+ pending_ms = timeout_ms - elapsed_ms;
+ if(pending_ms <= 0)
+ break;
+ } while(r == -1);
+#endif /* USE_WINSOCK */
+ if(r)
+ r = -1;
+ return r;
+}
+
+/*
+ * Wait for read or write events on a set of file descriptors. It uses poll()
+ * when a fine poll() is available, in order to avoid limits with FD_SETSIZE,
+ * otherwise select() is used. An error is returned if select() is being used
+ * and a file descriptor is too large for FD_SETSIZE.
+ *
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ * -1 = system call error or fd >= FD_SETSIZE
+ * 0 = timeout
+ * [bitmask] = action as described below
+ *
+ * CURL_CSELECT_IN - first socket is readable
+ * CURL_CSELECT_IN2 - second socket is readable
+ * CURL_CSELECT_OUT - write socket is writable
+ * CURL_CSELECT_ERR - an error condition occurred
+ */
+int Curl_socket_check(curl_socket_t readfd0, /* two sockets to read from */
+ curl_socket_t readfd1,
+ curl_socket_t writefd, /* socket to write to */
+ long timeout_ms) /* milliseconds to wait */
+{
+#ifdef HAVE_POLL_FINE
+ struct pollfd pfd[3];
+ int num;
+#else
+ struct timeval pending_tv;
+ struct timeval *ptimeout;
+ fd_set fds_read;
+ fd_set fds_write;
+ fd_set fds_err;
+ curl_socket_t maxfd;
+#endif
+ struct timeval initial_tv = {0,0};
+ int pending_ms = 0;
+ int error;
+ int r;
+ int ret;
+
+ if((readfd0 == CURL_SOCKET_BAD) && (readfd1 == CURL_SOCKET_BAD) &&
+ (writefd == CURL_SOCKET_BAD)) {
+ /* no sockets, just wait */
+ r = Curl_wait_ms((int)timeout_ms);
+ return r;
+ }
+
+ /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ time in this function does not need to be measured. This happens
+ when function is called with a zero timeout or a negative timeout
+ value indicating a blocking call should be performed. */
+
+ if(timeout_ms > 0) {
+ pending_ms = (int)timeout_ms;
+ initial_tv = curlx_tvnow();
+ }
+
+#ifdef HAVE_POLL_FINE
+
+ num = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ pfd[num].fd = readfd0;
+ pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+ pfd[num].revents = 0;
+ num++;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ pfd[num].fd = readfd1;
+ pfd[num].events = POLLRDNORM|POLLIN|POLLRDBAND|POLLPRI;
+ pfd[num].revents = 0;
+ num++;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ pfd[num].fd = writefd;
+ pfd[num].events = POLLWRNORM|POLLOUT;
+ pfd[num].revents = 0;
+ num++;
+ }
+
+ do {
+ if(timeout_ms < 0)
+ pending_ms = -1;
+ else if(!timeout_ms)
+ pending_ms = 0;
+ r = poll(pfd, num, pending_ms);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && error_not_EINTR)
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = (int)(timeout_ms - elapsed_ms);
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ ret = 0;
+ num = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+ ret |= CURL_CSELECT_IN;
+ if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ num++;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLRDNORM|POLLIN|POLLERR|POLLHUP))
+ ret |= CURL_CSELECT_IN2;
+ if(pfd[num].revents & (POLLRDBAND|POLLPRI|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ num++;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ if(pfd[num].revents & (POLLWRNORM|POLLOUT))
+ ret |= CURL_CSELECT_OUT;
+ if(pfd[num].revents & (POLLERR|POLLHUP|POLLNVAL))
+ ret |= CURL_CSELECT_ERR;
+ }
+
+ return ret;
+
+#else /* HAVE_POLL_FINE */
+
+ FD_ZERO(&fds_err);
+ maxfd = (curl_socket_t)-1;
+
+ FD_ZERO(&fds_read);
+ if(readfd0 != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(readfd0);
+ FD_SET(readfd0, &fds_read);
+ FD_SET(readfd0, &fds_err);
+ maxfd = readfd0;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(readfd1);
+ FD_SET(readfd1, &fds_read);
+ FD_SET(readfd1, &fds_err);
+ if(readfd1 > maxfd)
+ maxfd = readfd1;
+ }
+
+ FD_ZERO(&fds_write);
+ if(writefd != CURL_SOCKET_BAD) {
+ VERIFY_SOCK(writefd);
+ FD_SET(writefd, &fds_write);
+ FD_SET(writefd, &fds_err);
+ if(writefd > maxfd)
+ maxfd = writefd;
+ }
+
+ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+ do {
+ if(timeout_ms > 0) {
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ }
+ else if(!timeout_ms) {
+ pending_tv.tv_sec = 0;
+ pending_tv.tv_usec = 0;
+ }
+ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && error_not_EINTR)
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms - elapsed_ms;
+ if(pending_ms <= 0) {
+ r = 0; /* Simulate a "call timed out" case */
+ break;
+ }
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ ret = 0;
+ if(readfd0 != CURL_SOCKET_BAD) {
+ if(FD_ISSET(readfd0, &fds_read))
+ ret |= CURL_CSELECT_IN;
+ if(FD_ISSET(readfd0, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+ if(readfd1 != CURL_SOCKET_BAD) {
+ if(FD_ISSET(readfd1, &fds_read))
+ ret |= CURL_CSELECT_IN2;
+ if(FD_ISSET(readfd1, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+ if(writefd != CURL_SOCKET_BAD) {
+ if(FD_ISSET(writefd, &fds_write))
+ ret |= CURL_CSELECT_OUT;
+ if(FD_ISSET(writefd, &fds_err))
+ ret |= CURL_CSELECT_ERR;
+ }
+
+ return ret;
+
+#endif /* HAVE_POLL_FINE */
+
+}
+
+/*
+ * This is a wrapper around poll(). If poll() does not exist, then
+ * select() is used instead. An error is returned if select() is
+ * being used and a file descriptor is too large for FD_SETSIZE.
+ * A negative timeout value makes this function wait indefinitely,
+ * unles no valid file descriptor is given, when this happens the
+ * negative timeout is ignored and the function times out immediately.
+ *
+ * Return values:
+ * -1 = system call error or fd >= FD_SETSIZE
+ * 0 = timeout
+ * N = number of structures with non zero revent fields
+ */
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms)
+{
+#ifndef HAVE_POLL_FINE
+ struct timeval pending_tv;
+ struct timeval *ptimeout;
+ fd_set fds_read;
+ fd_set fds_write;
+ fd_set fds_err;
+ curl_socket_t maxfd;
+#endif
+ struct timeval initial_tv = {0,0};
+ bool fds_none = TRUE;
+ unsigned int i;
+ int pending_ms = 0;
+ int error;
+ int r;
+
+ if(ufds) {
+ for(i = 0; i < nfds; i++) {
+ if(ufds[i].fd != CURL_SOCKET_BAD) {
+ fds_none = FALSE;
+ break;
+ }
+ }
+ }
+ if(fds_none) {
+ r = Curl_wait_ms(timeout_ms);
+ return r;
+ }
+
+ /* Avoid initial timestamp, avoid curlx_tvnow() call, when elapsed
+ time in this function does not need to be measured. This happens
+ when function is called with a zero timeout or a negative timeout
+ value indicating a blocking call should be performed. */
+
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms;
+ initial_tv = curlx_tvnow();
+ }
+
+#ifdef HAVE_POLL_FINE
+
+ do {
+ if(timeout_ms < 0)
+ pending_ms = -1;
+ else if(!timeout_ms)
+ pending_ms = 0;
+ r = poll(ufds, nfds, pending_ms);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && error_not_EINTR)
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms - elapsed_ms;
+ if(pending_ms <= 0)
+ break;
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ for(i = 0; i < nfds; i++) {
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ if(ufds[i].revents & POLLHUP)
+ ufds[i].revents |= POLLIN;
+ if(ufds[i].revents & POLLERR)
+ ufds[i].revents |= (POLLIN|POLLOUT);
+ }
+
+#else /* HAVE_POLL_FINE */
+
+ FD_ZERO(&fds_read);
+ FD_ZERO(&fds_write);
+ FD_ZERO(&fds_err);
+ maxfd = (curl_socket_t)-1;
+
+ for(i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ VERIFY_SOCK(ufds[i].fd);
+ if(ufds[i].events & (POLLIN|POLLOUT|POLLPRI|
+ POLLRDNORM|POLLWRNORM|POLLRDBAND)) {
+ if(ufds[i].fd > maxfd)
+ maxfd = ufds[i].fd;
+ if(ufds[i].events & (POLLRDNORM|POLLIN))
+ FD_SET(ufds[i].fd, &fds_read);
+ if(ufds[i].events & (POLLWRNORM|POLLOUT))
+ FD_SET(ufds[i].fd, &fds_write);
+ if(ufds[i].events & (POLLRDBAND|POLLPRI))
+ FD_SET(ufds[i].fd, &fds_err);
+ }
+ }
+
+ ptimeout = (timeout_ms < 0) ? NULL : &pending_tv;
+
+ do {
+ if(timeout_ms > 0) {
+ pending_tv.tv_sec = pending_ms / 1000;
+ pending_tv.tv_usec = (pending_ms % 1000) * 1000;
+ }
+ else if(!timeout_ms) {
+ pending_tv.tv_sec = 0;
+ pending_tv.tv_usec = 0;
+ }
+ r = select((int)maxfd + 1, &fds_read, &fds_write, &fds_err, ptimeout);
+ if(r != -1)
+ break;
+ error = SOCKERRNO;
+ if(error && error_not_EINTR)
+ break;
+ if(timeout_ms > 0) {
+ pending_ms = timeout_ms - elapsed_ms;
+ if(pending_ms <= 0)
+ break;
+ }
+ } while(r == -1);
+
+ if(r < 0)
+ return -1;
+ if(r == 0)
+ return 0;
+
+ r = 0;
+ for(i = 0; i < nfds; i++) {
+ ufds[i].revents = 0;
+ if(ufds[i].fd == CURL_SOCKET_BAD)
+ continue;
+ if(FD_ISSET(ufds[i].fd, &fds_read))
+ ufds[i].revents |= POLLIN;
+ if(FD_ISSET(ufds[i].fd, &fds_write))
+ ufds[i].revents |= POLLOUT;
+ if(FD_ISSET(ufds[i].fd, &fds_err))
+ ufds[i].revents |= POLLPRI;
+ if(ufds[i].revents != 0)
+ r++;
+ }
+
+#endif /* HAVE_POLL_FINE */
+
+ return r;
+}
+
+#ifdef TPF
+/*
+ * This is a replacement for select() on the TPF platform.
+ * It is used whenever libcurl calls select().
+ * The call below to tpf_process_signals() is required because
+ * TPF's select calls are not signal interruptible.
+ *
+ * Return values are the same as select's.
+ */
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+ fd_set* excepts, struct timeval* tv)
+{
+ int rc;
+
+ rc = tpf_select_bsd(maxfds, reads, writes, excepts, tv);
+ tpf_process_signals();
+ return(rc);
+}
+#endif /* TPF */
diff --git a/libs/libcurl/src/select.h b/libs/libcurl/src/select.h
new file mode 100644
index 0000000000..c00afe166f
--- /dev/null
+++ b/libs/libcurl/src/select.h
@@ -0,0 +1,114 @@
+#ifndef HEADER_CURL_SELECT_H
+#define HEADER_CURL_SELECT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 HAVE_SYS_POLL_H
+#include <sys/poll.h>
+#elif defined(HAVE_POLL_H)
+#include <poll.h>
+#endif
+
+/*
+ * Definition of pollfd struct and constants for platforms lacking them.
+ */
+
+#if !defined(HAVE_STRUCT_POLLFD) && \
+ !defined(HAVE_SYS_POLL_H) && \
+ !defined(HAVE_POLL_H)
+
+#define POLLIN 0x01
+#define POLLPRI 0x02
+#define POLLOUT 0x04
+#define POLLERR 0x08
+#define POLLHUP 0x10
+#define POLLNVAL 0x20
+
+struct pollfd
+{
+ curl_socket_t fd;
+ short events;
+ short revents;
+};
+
+#endif
+
+#ifndef POLLRDNORM
+#define POLLRDNORM POLLIN
+#endif
+
+#ifndef POLLWRNORM
+#define POLLWRNORM POLLOUT
+#endif
+
+#ifndef POLLRDBAND
+#define POLLRDBAND POLLPRI
+#endif
+
+/* there are three CSELECT defines that are defined in the public header that
+ are exposed to users, but this *IN2 bit is only ever used internally and
+ therefore defined here */
+#define CURL_CSELECT_IN2 (CURL_CSELECT_ERR << 1)
+
+int Curl_socket_check(curl_socket_t readfd, curl_socket_t readfd2,
+ curl_socket_t writefd,
+ long timeout_ms);
+
+/* provide the former API internally */
+#define Curl_socket_ready(x,y,z) \
+ Curl_socket_check(x, CURL_SOCKET_BAD, y, z)
+
+int Curl_poll(struct pollfd ufds[], unsigned int nfds, int timeout_ms);
+
+/* On non-DOS and non-Winsock platforms, when Curl_ack_eintr is set,
+ * EINTR condition is honored and function might exit early without
+ * awaiting full timeout. Otherwise EINTR will be ignored and full
+ * timeout will elapse. */
+extern int Curl_ack_eintr;
+
+int Curl_wait_ms(int timeout_ms);
+
+#ifdef TPF
+int tpf_select_libcurl(int maxfds, fd_set* reads, fd_set* writes,
+ fd_set* excepts, struct timeval* tv);
+#endif
+
+/* Winsock and TPF sockets are not in range [0..FD_SETSIZE-1], which
+ unfortunately makes it impossible for us to easily check if they're valid
+*/
+#if defined(USE_WINSOCK) || defined(TPF)
+#define VALID_SOCK(x) 1
+#define VERIFY_SOCK(x) Curl_nop_stmt
+#else
+#define VALID_SOCK(s) (((s) >= 0) && ((s) < FD_SETSIZE))
+#define VERIFY_SOCK(x) do { \
+ if(!VALID_SOCK(x)) { \
+ SET_SOCKERRNO(EINVAL); \
+ return -1; \
+ } \
+} WHILE_FALSE
+#endif
+
+#endif /* HEADER_CURL_SELECT_H */
+
diff --git a/libs/libcurl/src/sendf.c b/libs/libcurl/src/sendf.c
new file mode 100644
index 0000000000..7b6fca6108
--- /dev/null
+++ b/libs/libcurl/src/sendf.c
@@ -0,0 +1,678 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 <curl/curl.h>
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "sslgen.h"
+#include "ssh.h"
+#include "multiif.h"
+#include "non-ascii.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+#include "strerror.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifdef CURL_DO_LINEEND_CONV
+/*
+ * convert_lineends() changes CRLF (\r\n) end-of-line markers to a single LF
+ * (\n), with special processing for CRLF sequences that are split between two
+ * blocks of data. Remaining, bare CRs are changed to LFs. The possibly new
+ * size of the data is returned.
+ */
+static size_t convert_lineends(struct SessionHandle *data,
+ char *startPtr, size_t size)
+{
+ char *inPtr, *outPtr;
+
+ /* sanity check */
+ if((startPtr == NULL) || (size < 1)) {
+ return(size);
+ }
+
+ if(data->state.prev_block_had_trailing_cr) {
+ /* The previous block of incoming data
+ had a trailing CR, which was turned into a LF. */
+ if(*startPtr == '\n') {
+ /* This block of incoming data starts with the
+ previous block's LF so get rid of it */
+ memmove(startPtr, startPtr+1, size-1);
+ size--;
+ /* and it wasn't a bare CR but a CRLF conversion instead */
+ data->state.crlf_conversions++;
+ }
+ data->state.prev_block_had_trailing_cr = FALSE; /* reset the flag */
+ }
+
+ /* find 1st CR, if any */
+ inPtr = outPtr = memchr(startPtr, '\r', size);
+ if(inPtr) {
+ /* at least one CR, now look for CRLF */
+ while(inPtr < (startPtr+size-1)) {
+ /* note that it's size-1, so we'll never look past the last byte */
+ if(memcmp(inPtr, "\r\n", 2) == 0) {
+ /* CRLF found, bump past the CR and copy the NL */
+ inPtr++;
+ *outPtr = *inPtr;
+ /* keep track of how many CRLFs we converted */
+ data->state.crlf_conversions++;
+ }
+ else {
+ if(*inPtr == '\r') {
+ /* lone CR, move LF instead */
+ *outPtr = '\n';
+ }
+ else {
+ /* not a CRLF nor a CR, just copy whatever it is */
+ *outPtr = *inPtr;
+ }
+ }
+ outPtr++;
+ inPtr++;
+ } /* end of while loop */
+
+ if(inPtr < startPtr+size) {
+ /* handle last byte */
+ if(*inPtr == '\r') {
+ /* deal with a CR at the end of the buffer */
+ *outPtr = '\n'; /* copy a NL instead */
+ /* note that a CRLF might be split across two blocks */
+ data->state.prev_block_had_trailing_cr = TRUE;
+ }
+ else {
+ /* copy last byte */
+ *outPtr = *inPtr;
+ }
+ outPtr++;
+ }
+ if(outPtr < startPtr+size)
+ /* tidy up by null terminating the now shorter data */
+ *outPtr = '\0';
+
+ return(outPtr - startPtr);
+ }
+ return(size);
+}
+#endif /* CURL_DO_LINEEND_CONV */
+
+/* Curl_infof() is for info message along the way */
+
+void Curl_infof(struct SessionHandle *data, const char *fmt, ...)
+{
+ if(data && data->set.verbose) {
+ va_list ap;
+ size_t len;
+ char print_buffer[2048 + 1];
+ va_start(ap, fmt);
+ vsnprintf(print_buffer, sizeof(print_buffer), fmt, ap);
+ va_end(ap);
+ len = strlen(print_buffer);
+ Curl_debug(data, CURLINFO_TEXT, print_buffer, len, NULL);
+ }
+}
+
+/* Curl_failf() is for messages stating why we failed.
+ * The message SHALL NOT include any LF or CR.
+ */
+
+void Curl_failf(struct SessionHandle *data, const char *fmt, ...)
+{
+ va_list ap;
+ size_t len;
+ va_start(ap, fmt);
+
+ vsnprintf(data->state.buffer, BUFSIZE, fmt, ap);
+
+ if(data->set.errorbuffer && !data->state.errorbuf) {
+ snprintf(data->set.errorbuffer, CURL_ERROR_SIZE, "%s", data->state.buffer);
+ data->state.errorbuf = TRUE; /* wrote error string */
+ }
+ if(data->set.verbose) {
+ len = strlen(data->state.buffer);
+ if(len < BUFSIZE - 1) {
+ data->state.buffer[len] = '\n';
+ data->state.buffer[++len] = '\0';
+ }
+ Curl_debug(data, CURLINFO_TEXT, data->state.buffer, len, NULL);
+ }
+
+ va_end(ap);
+}
+
+/* Curl_sendf() sends formated data to the server */
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *conn,
+ const char *fmt, ...)
+{
+ struct SessionHandle *data = conn->data;
+ ssize_t bytes_written;
+ size_t write_len;
+ CURLcode res = CURLE_OK;
+ char *s;
+ char *sptr;
+ va_list ap;
+ va_start(ap, fmt);
+ s = vaprintf(fmt, ap); /* returns an allocated string */
+ va_end(ap);
+ if(!s)
+ return CURLE_OUT_OF_MEMORY; /* failure */
+
+ bytes_written=0;
+ write_len = strlen(s);
+ sptr = s;
+
+ for(;;) {
+ /* Write the buffer to the socket */
+ res = Curl_write(conn, sockfd, sptr, write_len, &bytes_written);
+
+ if(CURLE_OK != res)
+ break;
+
+ if(data->set.verbose)
+ Curl_debug(data, CURLINFO_DATA_OUT, sptr, (size_t)bytes_written, conn);
+
+ if((size_t)bytes_written != write_len) {
+ /* if not all was written at once, we must advance the pointer, decrease
+ the size left and try again! */
+ write_len -= bytes_written;
+ sptr += bytes_written;
+ }
+ else
+ break;
+ }
+
+ free(s); /* free the output string */
+
+ return res;
+}
+
+/*
+ * Curl_write() is an internal write function that sends data to the
+ * server. Works with plain sockets, SCP, SSL or kerberos.
+ *
+ * If the write would block (CURLE_AGAIN), we return CURLE_OK and
+ * (*written == 0). Otherwise we return regular CURLcode value.
+ */
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem,
+ size_t len,
+ ssize_t *written)
+{
+ ssize_t bytes_written;
+ CURLcode curlcode = CURLE_OK;
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ bytes_written = conn->send[num](conn, num, mem, len, &curlcode);
+
+ *written = bytes_written;
+ if(bytes_written >= 0)
+ /* we completely ignore the curlcode value when subzero is not returned */
+ return CURLE_OK;
+
+ /* handle CURLE_AGAIN or a send failure */
+ switch(curlcode) {
+ case CURLE_AGAIN:
+ *written = 0;
+ return CURLE_OK;
+
+ case CURLE_OK:
+ /* general send failure */
+ return CURLE_SEND_ERROR;
+
+ default:
+ /* we got a specific curlcode, forward it */
+ return curlcode;
+ }
+}
+
+ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ const void *mem, size_t len, CURLcode *code)
+{
+ curl_socket_t sockfd = conn->sock[num];
+ ssize_t bytes_written = swrite(sockfd, mem, len);
+
+ *code = CURLE_OK;
+ if(-1 == bytes_written) {
+ int err = SOCKERRNO;
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefor
+ treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+ ) {
+ /* this is just a case of EWOULDBLOCK */
+ bytes_written=0;
+ *code = CURLE_AGAIN;
+ }
+ else {
+ failf(conn->data, "Send failure: %s",
+ Curl_strerror(conn, err));
+ conn->data->state.os_errno = err;
+ *code = CURLE_SEND_ERROR;
+ }
+ }
+ return bytes_written;
+}
+
+/*
+ * Curl_write_plain() is an internal write function that sends data to the
+ * server using plain sockets only. Otherwise meant to have the exact same
+ * proto as Curl_write()
+ */
+CURLcode Curl_write_plain(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem,
+ size_t len,
+ ssize_t *written)
+{
+ ssize_t bytes_written;
+ CURLcode retcode;
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ bytes_written = Curl_send_plain(conn, num, mem, len, &retcode);
+
+ *written = bytes_written;
+
+ return retcode;
+}
+
+ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ size_t len, CURLcode *code)
+{
+ curl_socket_t sockfd = conn->sock[num];
+ ssize_t nread = sread(sockfd, buf, len);
+
+ *code = CURLE_OK;
+ if(-1 == nread) {
+ int err = SOCKERRNO;
+
+ if(
+#ifdef WSAEWOULDBLOCK
+ /* This is how Windows does it */
+ (WSAEWOULDBLOCK == err)
+#else
+ /* errno may be EWOULDBLOCK or on some systems EAGAIN when it returned
+ due to its inability to send off data without blocking. We therefor
+ treat both error codes the same here */
+ (EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err)
+#endif
+ ) {
+ /* this is just a case of EWOULDBLOCK */
+ *code = CURLE_AGAIN;
+ }
+ else {
+ failf(conn->data, "Recv failure: %s",
+ Curl_strerror(conn, err));
+ conn->data->state.os_errno = err;
+ *code = CURLE_RECV_ERROR;
+ }
+ }
+ return nread;
+}
+
+static CURLcode pausewrite(struct SessionHandle *data,
+ int type, /* what type of data */
+ const char *ptr,
+ size_t len)
+{
+ /* signalled to pause sending on this connection, but since we have data
+ we want to send we need to dup it to save a copy for when the sending
+ is again enabled */
+ struct SingleRequest *k = &data->req;
+ char *dupl = malloc(len);
+ if(!dupl)
+ return CURLE_OUT_OF_MEMORY;
+
+ memcpy(dupl, ptr, len);
+
+ /* store this information in the state struct for later use */
+ data->state.tempwrite = dupl;
+ data->state.tempwritesize = len;
+ data->state.tempwritetype = type;
+
+ /* mark the connection as RECV paused */
+ k->keepon |= KEEP_RECV_PAUSE;
+
+ DEBUGF(infof(data, "Pausing with %zu bytes in buffer for type %02x\n",
+ len, type));
+
+ return CURLE_OK;
+}
+
+
+/* Curl_client_write() sends data to the write callback(s)
+
+ The bit pattern defines to what "streams" to write to. Body and/or header.
+ The defines are in sendf.h of course.
+
+ If CURL_DO_LINEEND_CONV is enabled, data is converted IN PLACE to the
+ local character encoding. This is a problem and should be changed in
+ the future to leave the original data alone.
+ */
+CURLcode Curl_client_write(struct connectdata *conn,
+ int type,
+ char *ptr,
+ size_t len)
+{
+ struct SessionHandle *data = conn->data;
+ size_t wrote;
+
+ if(0 == len)
+ len = strlen(ptr);
+
+ /* If reading is actually paused, we're forced to append this chunk of data
+ to the already held data, but only if it is the same type as otherwise it
+ can't work and it'll return error instead. */
+ if(data->req.keepon & KEEP_RECV_PAUSE) {
+ size_t newlen;
+ char *newptr;
+ if(type != data->state.tempwritetype)
+ /* major internal confusion */
+ return CURLE_RECV_ERROR;
+
+ DEBUGASSERT(data->state.tempwrite);
+
+ /* figure out the new size of the data to save */
+ newlen = len + data->state.tempwritesize;
+ /* allocate the new memory area */
+ newptr = realloc(data->state.tempwrite, newlen);
+ if(!newptr)
+ return CURLE_OUT_OF_MEMORY;
+ /* copy the new data to the end of the new area */
+ memcpy(newptr + data->state.tempwritesize, ptr, len);
+ /* update the pointer and the size */
+ data->state.tempwrite = newptr;
+ data->state.tempwritesize = newlen;
+
+ return CURLE_OK;
+ }
+
+ if(type & CLIENTWRITE_BODY) {
+ if((conn->handler->protocol&CURLPROTO_FTP) &&
+ conn->proto.ftpc.transfertype == 'A') {
+ /* convert from the network encoding */
+ CURLcode rc = Curl_convert_from_network(data, ptr, len);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ if(rc)
+ return rc;
+
+#ifdef CURL_DO_LINEEND_CONV
+ /* convert end-of-line markers */
+ len = convert_lineends(data, ptr, len);
+#endif /* CURL_DO_LINEEND_CONV */
+ }
+ /* If the previous block of data ended with CR and this block of data is
+ just a NL, then the length might be zero */
+ if(len) {
+ wrote = data->set.fwrite_func(ptr, 1, len, data->set.out);
+ }
+ else {
+ wrote = len;
+ }
+
+ if(CURL_WRITEFUNC_PAUSE == wrote)
+ return pausewrite(data, type, ptr, len);
+
+ if(wrote != len) {
+ failf(data, "Failed writing body (%zu != %zu)", wrote, len);
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ if((type & CLIENTWRITE_HEADER) &&
+ (data->set.fwrite_header || data->set.writeheader) ) {
+ /*
+ * Write headers to the same callback or to the especially setup
+ * header callback function (added after version 7.7.1).
+ */
+ curl_write_callback writeit=
+ data->set.fwrite_header?data->set.fwrite_header:data->set.fwrite_func;
+
+ /* Note: The header is in the host encoding
+ regardless of the ftp transfer mode (ASCII/Image) */
+
+ wrote = writeit(ptr, 1, len, data->set.writeheader);
+ if(CURL_WRITEFUNC_PAUSE == wrote)
+ /* here we pass in the HEADER bit only since if this was body as well
+ then it was passed already and clearly that didn't trigger the pause,
+ so this is saved for later with the HEADER bit only */
+ return pausewrite(data, CLIENTWRITE_HEADER, ptr, len);
+
+ if(wrote != len) {
+ failf (data, "Failed writing header");
+ return CURLE_WRITE_ERROR;
+ }
+ }
+
+ return CURLE_OK;
+}
+
+CURLcode Curl_read_plain(curl_socket_t sockfd,
+ char *buf,
+ size_t bytesfromsocket,
+ ssize_t *n)
+{
+ ssize_t nread = sread(sockfd, buf, bytesfromsocket);
+
+ if(-1 == nread) {
+ int err = SOCKERRNO;
+#ifdef USE_WINSOCK
+ if(WSAEWOULDBLOCK == err)
+#else
+ if((EWOULDBLOCK == err) || (EAGAIN == err) || (EINTR == err))
+#endif
+ return CURLE_AGAIN;
+ else
+ return CURLE_RECV_ERROR;
+ }
+
+ /* we only return number of bytes read when we return OK */
+ *n = nread;
+ return CURLE_OK;
+}
+
+/*
+ * Internal read-from-socket function. This is meant to deal with plain
+ * sockets, SSL sockets and kerberos sockets.
+ *
+ * Returns a regular CURLcode value.
+ */
+CURLcode Curl_read(struct connectdata *conn, /* connection data */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ size_t sizerequested, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
+{
+ CURLcode curlcode = CURLE_RECV_ERROR;
+ ssize_t nread = 0;
+ size_t bytesfromsocket = 0;
+ char *buffertofill = NULL;
+ bool pipelining = Curl_multi_pipeline_enabled(conn->data->multi);
+
+ /* Set 'num' to 0 or 1, depending on which socket that has been sent here.
+ If it is the second socket, we set num to 1. Otherwise to 0. This lets
+ us use the correct ssl handle. */
+ int num = (sockfd == conn->sock[SECONDARYSOCKET]);
+
+ *n=0; /* reset amount to zero */
+
+ /* If session can pipeline, check connection buffer */
+ if(pipelining) {
+ size_t bytestocopy = CURLMIN(conn->buf_len - conn->read_pos,
+ sizerequested);
+
+ /* Copy from our master buffer first if we have some unread data there*/
+ if(bytestocopy > 0) {
+ memcpy(buf, conn->master_buffer + conn->read_pos, bytestocopy);
+ conn->read_pos += bytestocopy;
+ conn->bits.stream_was_rewound = FALSE;
+
+ *n = (ssize_t)bytestocopy;
+ return CURLE_OK;
+ }
+ /* If we come here, it means that there is no data to read from the buffer,
+ * so we read from the socket */
+ bytesfromsocket = CURLMIN(sizerequested, BUFSIZE * sizeof (char));
+ buffertofill = conn->master_buffer;
+ }
+ else {
+ bytesfromsocket = CURLMIN((long)sizerequested,
+ conn->data->set.buffer_size ?
+ conn->data->set.buffer_size : BUFSIZE);
+ buffertofill = buf;
+ }
+
+ nread = conn->recv[num](conn, num, buffertofill, bytesfromsocket, &curlcode);
+ if(nread < 0)
+ return curlcode;
+
+ if(pipelining) {
+ memcpy(buf, conn->master_buffer, nread);
+ conn->buf_len = nread;
+ conn->read_pos = nread;
+ }
+
+ *n += nread;
+
+ return CURLE_OK;
+}
+
+/* return 0 on success */
+static int showit(struct SessionHandle *data, curl_infotype type,
+ char *ptr, size_t size)
+{
+ static const char s_infotype[CURLINFO_END][3] = {
+ "* ", "< ", "> ", "{ ", "} ", "{ ", "} " };
+
+#ifdef CURL_DOES_CONVERSIONS
+ char buf[BUFSIZE+1];
+ size_t conv_size = 0;
+
+ switch(type) {
+ case CURLINFO_HEADER_OUT:
+ /* assume output headers are ASCII */
+ /* copy the data into my buffer so the original is unchanged */
+ if(size > BUFSIZE) {
+ size = BUFSIZE; /* truncate if necessary */
+ buf[BUFSIZE] = '\0';
+ }
+ conv_size = size;
+ memcpy(buf, ptr, size);
+ /* Special processing is needed for this block if it
+ * contains both headers and data (separated by CRLFCRLF).
+ * We want to convert just the headers, leaving the data as-is.
+ */
+ if(size > 4) {
+ size_t i;
+ for(i = 0; i < size-4; i++) {
+ if(memcmp(&buf[i], "\x0d\x0a\x0d\x0a", 4) == 0) {
+ /* convert everything through this CRLFCRLF but no further */
+ conv_size = i + 4;
+ break;
+ }
+ }
+ }
+
+ Curl_convert_from_network(data, buf, conv_size);
+ /* Curl_convert_from_network calls failf if unsuccessful */
+ /* we might as well continue even if it fails... */
+ ptr = buf; /* switch pointer to use my buffer instead */
+ break;
+ default:
+ /* leave everything else as-is */
+ break;
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if(data->set.fdebug)
+ return (*data->set.fdebug)(data, type, ptr, size,
+ data->set.debugdata);
+
+ switch(type) {
+ case CURLINFO_TEXT:
+ case CURLINFO_HEADER_OUT:
+ case CURLINFO_HEADER_IN:
+ fwrite(s_infotype[type], 2, 1, data->set.err);
+ fwrite(ptr, size, 1, data->set.err);
+#ifdef CURL_DOES_CONVERSIONS
+ if(size != conv_size) {
+ /* we had untranslated data so we need an explicit newline */
+ fwrite("\n", 1, 1, data->set.err);
+ }
+#endif
+ break;
+ default: /* nada */
+ break;
+ }
+ return 0;
+}
+
+int Curl_debug(struct SessionHandle *data, curl_infotype type,
+ char *ptr, size_t size,
+ struct connectdata *conn)
+{
+ int rc;
+ if(data->set.printhost && conn && conn->host.dispname) {
+ char buffer[160];
+ const char *t=NULL;
+ const char *w="Data";
+ switch (type) {
+ case CURLINFO_HEADER_IN:
+ w = "Header";
+ case CURLINFO_DATA_IN:
+ t = "from";
+ break;
+ case CURLINFO_HEADER_OUT:
+ w = "Header";
+ case CURLINFO_DATA_OUT:
+ t = "to";
+ break;
+ default:
+ break;
+ }
+
+ if(t) {
+ snprintf(buffer, sizeof(buffer), "[%s %s %s]", w, t,
+ conn->host.dispname);
+ rc = showit(data, CURLINFO_TEXT, buffer, strlen(buffer));
+ if(rc)
+ return rc;
+ }
+ }
+ rc = showit(data, type, ptr, size);
+ return rc;
+}
diff --git a/libs/libcurl/src/sendf.h b/libs/libcurl/src/sendf.h
new file mode 100644
index 0000000000..39489e40fb
--- /dev/null
+++ b/libs/libcurl/src/sendf.h
@@ -0,0 +1,90 @@
+#ifndef HEADER_CURL_SENDF_H
+#define HEADER_CURL_SENDF_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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"
+
+CURLcode Curl_sendf(curl_socket_t sockfd, struct connectdata *,
+ const char *fmt, ...);
+void Curl_infof(struct SessionHandle *, const char *fmt, ...);
+void Curl_failf(struct SessionHandle *, const char *fmt, ...);
+
+#if defined(CURL_DISABLE_VERBOSE_STRINGS)
+
+#if defined(HAVE_VARIADIC_MACROS_C99)
+#define infof(...) Curl_nop_stmt
+#elif defined(HAVE_VARIADIC_MACROS_GCC)
+#define infof(x...) Curl_nop_stmt
+#else
+#define infof (void)
+#endif
+
+#else /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define infof Curl_infof
+
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+
+#define failf Curl_failf
+
+#define CLIENTWRITE_BODY (1<<0)
+#define CLIENTWRITE_HEADER (1<<1)
+#define CLIENTWRITE_BOTH (CLIENTWRITE_BODY|CLIENTWRITE_HEADER)
+
+CURLcode Curl_client_write(struct connectdata *conn, int type, char *ptr,
+ size_t len);
+
+/* internal read-function, does plain socket only */
+CURLcode Curl_read_plain(curl_socket_t sockfd,
+ char *buf,
+ size_t bytesfromsocket,
+ ssize_t *n);
+
+ssize_t Curl_recv_plain(struct connectdata *conn, int num, char *buf,
+ size_t len, CURLcode *code);
+ssize_t Curl_send_plain(struct connectdata *conn, int num,
+ const void *mem, size_t len, CURLcode *code);
+
+/* internal read-function, does plain socket, SSL and krb4 */
+CURLcode Curl_read(struct connectdata *conn, curl_socket_t sockfd,
+ char *buf, size_t buffersize,
+ ssize_t *n);
+/* internal write-function, does plain socket, SSL, SCP, SFTP and krb4 */
+CURLcode Curl_write(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem, size_t len,
+ ssize_t *written);
+
+/* internal write-function, does plain sockets ONLY */
+CURLcode Curl_write_plain(struct connectdata *conn,
+ curl_socket_t sockfd,
+ const void *mem, size_t len,
+ ssize_t *written);
+
+/* the function used to output verbose information */
+int Curl_debug(struct SessionHandle *handle, curl_infotype type,
+ char *data, size_t size,
+ struct connectdata *conn);
+
+
+#endif /* HEADER_CURL_SENDF_H */
diff --git a/libs/libcurl/src/setup-os400.h b/libs/libcurl/src/setup-os400.h
new file mode 100644
index 0000000000..319efec929
--- /dev/null
+++ b/libs/libcurl/src/setup-os400.h
@@ -0,0 +1,230 @@
+#ifndef HEADER_CURL_SETUP_OS400_H
+#define HEADER_CURL_SETUP_OS400_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.
+ *
+ ***************************************************************************/
+
+
+/* OS/400 netdb.h does not define NI_MAXHOST. */
+#define NI_MAXHOST 1025
+
+/* OS/400 netdb.h does not define NI_MAXSERV. */
+#define NI_MAXSERV 32
+
+/* No OS/400 header file defines u_int32_t. */
+typedef unsigned long u_int32_t;
+
+
+/* System API wrapper prototypes and definitions to support ASCII parameters. */
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <qsossl.h>
+#include <gskssl.h>
+#include <qsoasync.h>
+#include <gssapi.h>
+
+extern int Curl_getaddrinfo_a(const char * nodename, const char * servname,
+ const struct addrinfo * hints,
+ struct addrinfo * * res);
+#define getaddrinfo Curl_getaddrinfo_a
+
+
+extern int Curl_getnameinfo_a(const struct sockaddr * sa,
+ curl_socklen_t salen,
+ char * nodename, curl_socklen_t nodenamelen,
+ char * servname, curl_socklen_t servnamelen,
+ int flags);
+#define getnameinfo Curl_getnameinfo_a
+
+
+/* SSL wrappers. */
+
+extern int Curl_SSL_Init_Application_a(SSLInitApp * init_app);
+#define SSL_Init_Application Curl_SSL_Init_Application_a
+
+
+extern int Curl_SSL_Init_a(SSLInit * init);
+#define SSL_Init Curl_SSL_Init_a
+
+
+extern char * Curl_SSL_Strerror_a(int sslreturnvalue, SSLErrorMsg * serrmsgp);
+#define SSL_Strerror Curl_SSL_Strerror_a
+
+
+/* GSKit wrappers. */
+
+extern int Curl_gsk_environment_open(gsk_handle * my_env_handle);
+#define gsk_environment_open Curl_gsk_environment_open
+
+extern int Curl_gsk_secure_soc_open(gsk_handle my_env_handle,
+ gsk_handle * my_session_handle);
+#define gsk_secure_soc_open Curl_gsk_secure_soc_open
+
+extern int Curl_gsk_environment_close(gsk_handle * my_env_handle);
+#define gsk_environment_close Curl_gsk_environment_close
+
+extern int Curl_gsk_secure_soc_close(gsk_handle * my_session_handle);
+#define gsk_secure_soc_close Curl_gsk_secure_soc_close
+
+extern int Curl_gsk_environment_init(gsk_handle my_env_handle);
+#define gsk_environment_init Curl_gsk_environment_init
+
+extern int Curl_gsk_secure_soc_init(gsk_handle my_session_handle);
+#define gsk_secure_soc_init Curl_gsk_secure_soc_init
+
+extern int Curl_gsk_attribute_set_buffer_a(gsk_handle my_gsk_handle,
+ GSK_BUF_ID bufID,
+ const char * buffer,
+ int bufSize);
+#define gsk_attribute_set_buffer Curl_gsk_attribute_set_buffer_a
+
+extern int Curl_gsk_attribute_set_enum(gsk_handle my_gsk_handle,
+ GSK_ENUM_ID enumID,
+ GSK_ENUM_VALUE enumValue);
+#define gsk_attribute_set_enum Curl_gsk_attribute_set_enum
+
+extern int Curl_gsk_attribute_set_numeric_value(gsk_handle my_gsk_handle,
+ GSK_NUM_ID numID,
+ int numValue);
+#define gsk_attribute_set_numeric_value Curl_gsk_attribute_set_numeric_value
+
+extern int Curl_gsk_attribute_set_callback(gsk_handle my_gsk_handle,
+ GSK_CALLBACK_ID callBackID,
+ void * callBackAreaPtr);
+#define gsk_attribute_set_callback Curl_gsk_attribute_set_callback
+
+extern int Curl_gsk_attribute_get_buffer_a(gsk_handle my_gsk_handle,
+ GSK_BUF_ID bufID,
+ const char * * buffer,
+ int * bufSize);
+#define gsk_attribute_get_buffer Curl_gsk_attribute_get_buffer_a
+
+extern int Curl_gsk_attribute_get_enum(gsk_handle my_gsk_handle,
+ GSK_ENUM_ID enumID,
+ GSK_ENUM_VALUE * enumValue);
+#define gsk_attribute_get_enum Curl_gsk_attribute_get_enum
+
+extern int Curl_gsk_attribute_get_numeric_value(gsk_handle my_gsk_handle,
+ GSK_NUM_ID numID,
+ int * numValue);
+#define gsk_attribute_get_numeric_value Curl_gsk_attribute_get_numeric_value
+
+extern int Curl_gsk_attribute_get_cert_info(gsk_handle my_gsk_handle,
+ GSK_CERT_ID certID,
+ const gsk_cert_data_elem * * certDataElem,
+ int * certDataElementCount);
+#define gsk_attribute_get_cert_info Curl_gsk_attribute_get_cert_info
+
+extern int Curl_gsk_secure_soc_misc(gsk_handle my_session_handle,
+ GSK_MISC_ID miscID);
+#define gsk_secure_soc_misc Curl_gsk_secure_soc_misc
+
+extern int Curl_gsk_secure_soc_read(gsk_handle my_session_handle,
+ char * readBuffer,
+ int readBufSize, int * amtRead);
+#define gsk_secure_soc_read Curl_gsk_secure_soc_read
+
+extern int Curl_gsk_secure_soc_write(gsk_handle my_session_handle,
+ char * writeBuffer,
+ int writeBufSize, int * amtWritten);
+#define gsk_secure_soc_write Curl_gsk_secure_soc_write
+
+extern const char * Curl_gsk_strerror_a(int gsk_return_value);
+#define gsk_strerror Curl_gsk_strerror_a
+
+extern int Curl_gsk_secure_soc_startInit(gsk_handle my_session_handle,
+ int IOCompletionPort,
+ Qso_OverlappedIO_t * communicationsArea);
+#define gsk_secure_soc_startInit Curl_gsk_secure_soc_startInit
+
+
+/* GSSAPI wrappers. */
+
+extern OM_uint32 Curl_gss_import_name_a(OM_uint32 * minor_status,
+ gss_buffer_t in_name,
+ gss_OID in_name_type,
+ gss_name_t * out_name);
+#define gss_import_name Curl_gss_import_name_a
+
+
+extern OM_uint32 Curl_gss_display_status_a(OM_uint32 * minor_status,
+ OM_uint32 status_value,
+ int status_type, gss_OID mech_type,
+ gss_msg_ctx_t * message_context,
+ gss_buffer_t status_string);
+#define gss_display_status Curl_gss_display_status_a
+
+
+extern OM_uint32 Curl_gss_init_sec_context_a(OM_uint32 * minor_status,
+ gss_cred_id_t cred_handle,
+ gss_ctx_id_t * context_handle,
+ gss_name_t target_name,
+ gss_OID mech_type,
+ gss_flags_t req_flags,
+ OM_uint32 time_req,
+ gss_channel_bindings_t
+ input_chan_bindings,
+ gss_buffer_t input_token,
+ gss_OID * actual_mech_type,
+ gss_buffer_t output_token,
+ gss_flags_t * ret_flags,
+ OM_uint32 * time_rec);
+#define gss_init_sec_context Curl_gss_init_sec_context_a
+
+
+extern OM_uint32 Curl_gss_delete_sec_context_a(OM_uint32 * minor_status,
+ gss_ctx_id_t * context_handle,
+ gss_buffer_t output_token);
+#define gss_delete_sec_context Curl_gss_delete_sec_context_a
+
+
+/* LDAP wrappers. */
+
+#define BerValue struct berval
+
+#define ldap_url_parse ldap_url_parse_utf8
+#define ldap_init Curl_ldap_init_a
+#define ldap_simple_bind_s Curl_ldap_simple_bind_s_a
+#define ldap_search_s Curl_ldap_search_s_a
+#define ldap_get_values_len Curl_ldap_get_values_len_a
+#define ldap_err2string Curl_ldap_err2string_a
+#define ldap_get_dn Curl_ldap_get_dn_a
+#define ldap_first_attribute Curl_ldap_first_attribute_a
+#define ldap_next_attribute Curl_ldap_next_attribute_a
+
+/* Some socket functions must be wrapped to process textual addresses
+ like AF_UNIX. */
+
+extern int Curl_os400_connect(int sd, struct sockaddr * destaddr, int addrlen);
+extern int Curl_os400_bind(int sd, struct sockaddr * localaddr, int addrlen);
+extern int Curl_os400_sendto(int sd, char * buffer, int buflen, int flags,
+ struct sockaddr * dstaddr, int addrlen);
+extern int Curl_os400_recvfrom(int sd, char * buffer, int buflen, int flags,
+ struct sockaddr * fromaddr, int * addrlen);
+
+#define connect Curl_os400_connect
+#define bind Curl_os400_bind
+#define sendto Curl_os400_sendto
+#define recvfrom Curl_os400_recvfrom
+
+
+#endif /* HEADER_CURL_SETUP_OS400_H */
diff --git a/libs/libcurl/src/setup-vms.h b/libs/libcurl/src/setup-vms.h
new file mode 100644
index 0000000000..f5eedf7566
--- /dev/null
+++ b/libs/libcurl/src/setup-vms.h
@@ -0,0 +1,399 @@
+#ifndef HEADER_CURL_SETUP_VMS_H
+#define HEADER_CURL_SETUP_VMS_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.
+ *
+ ***************************************************************************/
+
+/* */
+/* JEM, 12/30/12, VMS now generates config.h, so only define wrappers for */
+/* getenv(), getpwuid() and provide is_vms_shell() */
+/* Also need upper case symbols for system services, and */
+/* OpenSSL, and some Kerberos image */
+
+#ifdef __DECC
+#pragma message save
+#pragma message disable dollarid
+#endif
+
+/* Hide the stuff we are overriding */
+#define getenv decc_getenv
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE != 64
+# define getpwuid decc_getpwuid
+# endif
+#endif
+#include <stdlib.h>
+ char * decc$getenv(const char * __name);
+#include <pwd.h>
+
+#include <string.h>
+#include <unixlib.h>
+
+#undef getenv
+#undef getpwuid
+#define getenv vms_getenv
+#define getpwuid vms_getpwuid
+
+/* VAX needs these in upper case when compiling exact case */
+#define sys$assign SYS$ASSIGN
+#define sys$dassgn SYS$DASSGN
+#define sys$qiow SYS$QIOW
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+# pragma __pointer_size __save
+# endif
+#endif
+
+#if __USE_LONG_GID_T
+# define decc_getpwuid DECC$__LONG_GID_GETPWUID
+#else
+# if __INITIAL_POINTER_SIZE
+# define decc_getpwuid decc$__32_getpwuid
+# else
+# define decc_getpwuid decc$getpwuid
+# endif
+#endif
+
+ struct passwd * decc_getpwuid(uid_t uid);
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE == 32
+/* Translate the path, but only if the path is a VMS file specification */
+/* The translation is usually only needed for older versions of VMS */
+static char * vms_translate_path(const char * path) {
+char * unix_path;
+char * test_str;
+
+ /* See if the result is in VMS format, if not, we are done */
+ /* Assume that this is a PATH, not just some data */
+ test_str = strpbrk(path, ":[<^");
+ if(test_str == NULL) {
+ return (char *)path;
+ }
+
+ unix_path = decc$translate_vms(path);
+
+ if((int)unix_path <= 0) {
+ /* We can not translate it, so return the original string */
+ return (char *)path;
+ }
+}
+# else
+ /* VMS translate path is actually not needed on the current 64 bit */
+ /* VMS platforms, so instead of figuring out the pointer settings */
+ /* Change it to a noop */
+# define vms_translate_path(__path) __path
+# endif
+#endif
+
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+# pragma __pointer_size __restore
+# endif
+#endif
+
+static char * vms_getenv(const char * envvar) {
+
+char * result;
+char * vms_path;
+
+ /* first use the DECC getenv() function */
+ result = decc$getenv(envvar);
+ if(result == NULL) {
+ return result;
+ }
+
+ vms_path = result;
+ result = vms_translate_path(vms_path);
+
+ /* note that if you backport this to use VAX C RTL, that the VAX C RTL */
+ /* may do a malloc(2048) for each call to getenv(), so you will need */
+ /* to add a free(vms_path) */
+ /* Do not do a free() for DEC C RTL builds, which should be used for */
+ /* VMS 5.5-2 and later, even if using GCC */
+
+ return result;
+}
+
+
+static struct passwd vms_passwd_cache;
+
+static struct passwd * vms_getpwuid(uid_t uid) {
+
+struct passwd * my_passwd;
+
+/* Hack needed to support 64 bit builds, decc_getpwnam is 32 bit only */
+#ifdef __DECC
+# if __INITIAL_POINTER_SIZE
+__char_ptr32 unix_path;
+# else
+char * unix_path;
+# endif
+#else
+char * unix_path;
+#endif
+
+ my_passwd = decc_getpwuid(uid);
+ if(my_passwd == NULL) {
+ return my_passwd;
+ }
+
+ unix_path = vms_translate_path(my_passwd->pw_dir);
+
+ if((long)unix_path <= 0) {
+ /* We can not translate it, so return the original string */
+ return my_passwd;
+ }
+
+ /* If no changes needed just return it */
+ if(unix_path == my_passwd->pw_dir) {
+ return my_passwd;
+ }
+
+ /* Need to copy the structure returned */
+ /* Since curl is only using pw_dir, no need to fix up *
+ /* the pw_shell when running under Bash */
+ vms_passwd_cache.pw_name = my_passwd->pw_name;
+ vms_passwd_cache.pw_uid = my_passwd->pw_uid;
+ vms_passwd_cache.pw_gid = my_passwd->pw_uid;
+ vms_passwd_cache.pw_dir = unix_path;
+ vms_passwd_cache.pw_shell = my_passwd->pw_shell;
+
+ return &vms_passwd_cache;
+}
+
+#ifdef __DECC
+#pragma message restore
+#endif
+
+/* Bug - VMS OpenSSL and Kerberos universal symbols are in uppercase only */
+/* VMS libraries should have universal symbols in exact and uppercase */
+
+#define ASN1_INTEGER_get ASN1_INTEGER_GET
+#define ASN1_STRING_data ASN1_STRING_DATA
+#define ASN1_STRING_length ASN1_STRING_LENGTH
+#define ASN1_STRING_print ASN1_STRING_PRINT
+#define ASN1_STRING_to_UTF8 ASN1_STRING_TO_UTF8
+#define ASN1_STRING_type ASN1_STRING_TYPE
+#define BIO_ctrl BIO_CTRL
+#define BIO_free BIO_FREE
+#define BIO_new BIO_NEW
+#define BIO_s_mem BIO_S_MEM
+#define BN_bn2bin BN_BN2BIN
+#define BN_num_bits BN_NUM_BITS
+#define CRYPTO_cleanup_all_ex_data CRYPTO_CLEANUP_ALL_EX_DATA
+#define CRYPTO_free CRYPTO_FREE
+#define CRYPTO_malloc CRYPTO_MALLOC
+#define DES_ecb_encrypt DES_ECB_ENCRYPT
+#define DES_set_key DES_SET_KEY
+#define DES_set_odd_parity DES_SET_ODD_PARITY
+#define ENGINE_ctrl ENGINE_CTRL
+#define ENGINE_ctrl_cmd ENGINE_CTRL_CMD
+#define ENGINE_finish ENGINE_FINISH
+#define ENGINE_free ENGINE_FREE
+#define ENGINE_get_first ENGINE_GET_FIRST
+#define ENGINE_get_id ENGINE_GET_ID
+#define ENGINE_get_next ENGINE_GET_NEXT
+#define ENGINE_init ENGINE_INIT
+#define ENGINE_load_builtin_engines ENGINE_LOAD_BUILTIN_ENGINES
+#define ENGINE_load_private_key ENGINE_LOAD_PRIVATE_KEY
+#define ENGINE_set_default ENGINE_SET_DEFAULT
+#define ERR_clear_error ERR_CLEAR_ERROR
+#define ERR_error_string ERR_ERROR_STRING
+#define ERR_error_string_n ERR_ERROR_STRING_N
+#define ERR_free_strings ERR_FREE_STRINGS
+#define ERR_get_error ERR_GET_ERROR
+#define ERR_peek_error ERR_PEEK_ERROR
+#define ERR_remove_state ERR_REMOVE_STATE
+#define EVP_PKEY_copy_parameters EVP_PKEY_COPY_PARAMETERS
+#define EVP_PKEY_free EVP_PKEY_FREE
+#define EVP_cleanup EVP_CLEANUP
+#define GENERAL_NAMES_free GENERAL_NAMES_FREE
+#define MD4_Final MD4_FINAL
+#define MD4_Init MD4_INIT
+#define MD4_Update MD4_UPDATE
+#define MD5_Final MD5_FINAL
+#define MD5_Init MD5_INIT
+#define MD5_Update MD5_UPDATE
+#define OPENSSL_add_all_algo_noconf OPENSSL_ADD_ALL_ALGO_NOCONF
+#define PEM_read_X509 PEM_READ_X509
+#define PEM_write_bio_X509 PEM_WRITE_BIO_X509
+#define PKCS12_PBE_add PKCS12_PBE_ADD
+#define PKCS12_free PKCS12_FREE
+#define PKCS12_parse PKCS12_PARSE
+#define RAND_add RAND_ADD
+#define RAND_bytes RAND_BYTES
+#define RAND_egd RAND_EGD
+#define RAND_file_name RAND_FILE_NAME
+#define RAND_load_file RAND_LOAD_FILE
+#define RAND_status RAND_STATUS
+#define SSL_CIPHER_get_name SSL_CIPHER_GET_NAME
+#define SSL_CTX_add_client_CA SSL_CTX_ADD_CLIENT_CA
+#define SSL_CTX_callback_ctrl SSL_CTX_CALLBACK_CTRL
+#define SSL_CTX_check_private_key SSL_CTX_CHECK_PRIVATE_KEY
+#define SSL_CTX_ctrl SSL_CTX_CTRL
+#define SSL_CTX_free SSL_CTX_FREE
+#define SSL_CTX_get_cert_store SSL_CTX_GET_CERT_STORE
+#define SSL_CTX_load_verify_locations SSL_CTX_LOAD_VERIFY_LOCATIONS
+#define SSL_CTX_new SSL_CTX_NEW
+#define SSL_CTX_set_cipher_list SSL_CTX_SET_CIPHER_LIST
+#define SSL_CTX_set_def_passwd_cb_ud SSL_CTX_SET_DEF_PASSWD_CB_UD
+#define SSL_CTX_set_default_passwd_cb SSL_CTX_SET_DEFAULT_PASSWD_CB
+#define SSL_CTX_set_verify SSL_CTX_SET_VERIFY
+#define SSL_CTX_use_PrivateKey SSL_CTX_USE_PRIVATEKEY
+#define SSL_CTX_use_PrivateKey_file SSL_CTX_USE_PRIVATEKEY_FILE
+#define SSL_CTX_use_cert_chain_file SSL_CTX_USE_CERT_CHAIN_FILE
+#define SSL_CTX_use_certificate SSL_CTX_USE_CERTIFICATE
+#define SSL_CTX_use_certificate_file SSL_CTX_USE_CERTIFICATE_FILE
+#define SSL_SESSION_free SSL_SESSION_FREE
+#define SSL_connect SSL_CONNECT
+#define SSL_free SSL_FREE
+#define SSL_get1_session SSL_GET1_SESSION
+#define SSL_get_certificate SSL_GET_CERTIFICATE
+#define SSL_get_current_cipher SSL_GET_CURRENT_CIPHER
+#define SSL_get_error SSL_GET_ERROR
+#define SSL_get_peer_cert_chain SSL_GET_PEER_CERT_CHAIN
+#define SSL_get_peer_certificate SSL_GET_PEER_CERTIFICATE
+#define SSL_get_privatekey SSL_GET_PRIVATEKEY
+#define SSL_get_shutdown SSL_GET_SHUTDOWN
+#define SSL_get_verify_result SSL_GET_VERIFY_RESULT
+#define SSL_library_init SSL_LIBRARY_INIT
+#define SSL_load_error_strings SSL_LOAD_ERROR_STRINGS
+#define SSL_new SSL_NEW
+#define SSL_peek SSL_PEEK
+#define SSL_pending SSL_PENDING
+#define SSL_read SSL_READ
+#define SSL_set_connect_state SSL_SET_CONNECT_STATE
+#define SSL_set_fd SSL_SET_FD
+#define SSL_set_session SSL_SET_SESSION
+#define SSL_shutdown SSL_SHUTDOWN
+#define SSL_write SSL_WRITE
+#define SSLeay SSLEAY
+#define SSLv23_client_method SSLV23_CLIENT_METHOD
+#define SSLv3_client_method SSLV3_CLIENT_METHOD
+#define TLSv1_client_method TLSV1_CLIENT_METHOD
+#define UI_OpenSSL UI_OPENSSL
+#define X509V3_EXT_print X509V3_EXT_PRINT
+#define X509_EXTENSION_get_critical X509_EXTENSION_GET_CRITICAL
+#define X509_EXTENSION_get_object X509_EXTENSION_GET_OBJECT
+#define X509_LOOKUP_file X509_LOOKUP_FILE
+#define X509_NAME_ENTRY_get_data X509_NAME_ENTRY_GET_DATA
+#define X509_NAME_get_entry X509_NAME_GET_ENTRY
+#define X509_NAME_get_index_by_NID X509_NAME_GET_INDEX_BY_NID
+#define X509_NAME_print_ex X509_NAME_PRINT_EX
+#define X509_STORE_CTX_get_current_cert X509_STORE_CTX_GET_CURRENT_CERT
+#define X509_STORE_add_lookup X509_STORE_ADD_LOOKUP
+#define X509_STORE_set_flags X509_STORE_SET_FLAGS
+#define X509_check_issued X509_CHECK_ISSUED
+#define X509_free X509_FREE
+#define X509_get_ext_d2i X509_GET_EXT_D2I
+#define X509_get_issuer_name X509_GET_ISSUER_NAME
+#define X509_get_pubkey X509_GET_PUBKEY
+#define X509_get_serialNumber X509_GET_SERIALNUMBER
+#define X509_get_subject_name X509_GET_SUBJECT_NAME
+#define X509_load_crl_file X509_LOAD_CRL_FILE
+#define X509_verify_cert_error_string X509_VERIFY_CERT_ERROR_STRING
+#define d2i_PKCS12_fp D2I_PKCS12_FP
+#define i2t_ASN1_OBJECT I2T_ASN1_OBJECT
+#define sk_num SK_NUM
+#define sk_pop SK_POP
+#define sk_pop_free SK_POP_FREE
+#define sk_value SK_VALUE
+
+#define USE_UPPERCASE_GSSAPI 1
+#define gss_seal GSS_SEAL
+#define gss_unseal GSS_UNSEAL
+
+#define USE_UPPERCASE_KRBAPI 1
+
+/* AI_NUMERICHOST needed for IP V6 support in Curl */
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#ifndef AI_NUMERICHOST
+#ifdef ENABLE_IPV6
+#undef ENABLE_IPV6
+#endif
+#endif
+#endif
+
+/* VAX symbols are always in uppercase */
+#ifdef __VAX
+#define inflate INFLATE
+#define inflateEnd INFLATEEND
+#define inflateInit2_ INFLATEINIT2_
+#define inflateInit_ INFLATEINIT_
+#define zlibVersion ZLIBVERSION
+#endif
+
+/* Older VAX OpenSSL port defines these as Macros */
+/* Need to include the headers first and then redefine */
+/* that way a newer port will also work if some one has one */
+#ifdef __VAX
+
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+# define des_set_odd_parity DES_SET_ODD_PARITY
+# define des_set_key DES_SET_KEY
+# define des_ecb_encrypt DES_ECB_ENCRYPT
+
+# endif
+# include <openssl/evp.h>
+# ifndef OpenSSL_add_all_algorithms
+# define OpenSSL_add_all_algorithms OPENSSL_ADD_ALL_ALGORITHMS
+ void OPENSSL_ADD_ALL_ALGORITHMS(void);
+# endif
+
+ /* Curl defines these to lower case and VAX needs them in upper case */
+ /* So we need static routines */
+# if (OPENSSL_VERSION_NUMBER < 0x00907001L)
+
+# undef des_set_odd_parity
+# undef DES_set_odd_parity
+# undef des_set_key
+# undef DES_set_key
+# undef des_ecb_encrypt
+# undef DES_ecb_encrypt
+
+ static void des_set_odd_parity(des_cblock *key) {
+ DES_SET_ODD_PARITY(key);
+ }
+
+ static int des_set_key(const_des_cblock *key,
+ des_key_schedule schedule) {
+ return DES_SET_KEY(key, schedule);
+ }
+
+ static void des_ecb_encrypt(const_des_cblock *input,
+ des_cblock *output,
+ des_key_schedule ks,int enc) {
+ DES_ECB_ENCRYPT(input, output, ks, enc);
+ }
+#endif
+/* Need this to stop a macro redefinition error */
+#if OPENSSL_VERSION_NUMBER < 0x00907000L
+# ifdef X509_STORE_set_flags
+# undef X509_STORE_set_flags
+# define X509_STORE_set_flags(x,y) Curl_nop_stmt
+# endif
+#endif
+#endif
+
+#endif /* HEADER_CURL_SETUP_VMS_H */
diff --git a/libs/libcurl/src/share.c b/libs/libcurl/src/share.c
new file mode 100644
index 0000000000..b21c9f6852
--- /dev/null
+++ b/libs/libcurl/src/share.c
@@ -0,0 +1,254 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 <curl/curl.h>
+#include "urldata.h"
+#include "share.h"
+#include "sslgen.h"
+#include "curl_memory.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+CURLSH *
+curl_share_init(void)
+{
+ struct Curl_share *share = calloc(1, sizeof(struct Curl_share));
+ if(share)
+ share->specifier |= (1<<CURL_LOCK_DATA_SHARE);
+
+ return share;
+}
+
+#undef curl_share_setopt
+CURLSHcode
+curl_share_setopt(CURLSH *sh, CURLSHoption option, ...)
+{
+ struct Curl_share *share = (struct Curl_share *)sh;
+ va_list param;
+ int type;
+ curl_lock_function lockfunc;
+ curl_unlock_function unlockfunc;
+ void *ptr;
+ CURLSHcode res = CURLSHE_OK;
+
+ if(share->dirty)
+ /* don't allow setting options while one or more handles are already
+ using this share */
+ return CURLSHE_IN_USE;
+
+ va_start(param, option);
+
+ switch(option) {
+ case CURLSHOPT_SHARE:
+ /* this is a type this share will share */
+ type = va_arg(param, int);
+ share->specifier |= (1<<type);
+ switch( type ) {
+ case CURL_LOCK_DATA_DNS:
+ if(!share->hostcache) {
+ share->hostcache = Curl_mk_dnscache();
+ if(!share->hostcache)
+ res = CURLSHE_NOMEM;
+ }
+ break;
+
+ case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(!share->cookies) {
+ share->cookies = Curl_cookie_init(NULL, NULL, NULL, TRUE );
+ if(!share->cookies)
+ res = CURLSHE_NOMEM;
+ }
+#else /* CURL_DISABLE_HTTP */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+ if(!share->sslsession) {
+ share->max_ssl_sessions = 8;
+ share->sslsession = calloc(share->max_ssl_sessions,
+ sizeof(struct curl_ssl_session));
+ share->sessionage = 0;
+ if(!share->sslsession)
+ res = CURLSHE_NOMEM;
+ }
+#else
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_CONNECT: /* not supported (yet) */
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ }
+ break;
+
+ case CURLSHOPT_UNSHARE:
+ /* this is a type this share will no longer share */
+ type = va_arg(param, int);
+ share->specifier &= ~(1<<type);
+ switch( type ) {
+ case CURL_LOCK_DATA_DNS:
+ if(share->hostcache) {
+ Curl_hash_destroy(share->hostcache);
+ share->hostcache = NULL;
+ }
+ break;
+
+ case CURL_LOCK_DATA_COOKIE:
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(share->cookies) {
+ Curl_cookie_cleanup(share->cookies);
+ share->cookies = NULL;
+ }
+#else /* CURL_DISABLE_HTTP */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_SSL_SESSION:
+#ifdef USE_SSL
+ Curl_safefree(share->sslsession);
+#else
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
+ case CURL_LOCK_DATA_CONNECT:
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ break;
+ }
+ break;
+
+ case CURLSHOPT_LOCKFUNC:
+ lockfunc = va_arg(param, curl_lock_function);
+ share->lockfunc = lockfunc;
+ break;
+
+ case CURLSHOPT_UNLOCKFUNC:
+ unlockfunc = va_arg(param, curl_unlock_function);
+ share->unlockfunc = unlockfunc;
+ break;
+
+ case CURLSHOPT_USERDATA:
+ ptr = va_arg(param, void *);
+ share->clientdata = ptr;
+ break;
+
+ default:
+ res = CURLSHE_BAD_OPTION;
+ break;
+ }
+
+ va_end(param);
+
+ return res;
+}
+
+CURLSHcode
+curl_share_cleanup(CURLSH *sh)
+{
+ struct Curl_share *share = (struct Curl_share *)sh;
+
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->lockfunc)
+ share->lockfunc(NULL, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE,
+ share->clientdata);
+
+ if(share->dirty) {
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ return CURLSHE_IN_USE;
+ }
+
+ if(share->hostcache) {
+ Curl_hash_destroy(share->hostcache);
+ share->hostcache = NULL;
+ }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(share->cookies)
+ Curl_cookie_cleanup(share->cookies);
+#endif
+
+#ifdef USE_SSL
+ if(share->sslsession) {
+ size_t i;
+ for(i = 0; i < share->max_ssl_sessions; i++)
+ Curl_ssl_kill_session(&(share->sslsession[i]));
+ free(share->sslsession);
+ }
+#endif
+
+ if(share->unlockfunc)
+ share->unlockfunc(NULL, CURL_LOCK_DATA_SHARE, share->clientdata);
+ free(share);
+
+ return CURLSHE_OK;
+}
+
+
+CURLSHcode
+Curl_share_lock(struct SessionHandle *data, curl_lock_data type,
+ curl_lock_access accesstype)
+{
+ struct Curl_share *share = data->share;
+
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->lockfunc) /* only call this if set! */
+ share->lockfunc(data, type, accesstype, share->clientdata);
+ }
+ /* else if we don't share this, pretend successful lock */
+
+ return CURLSHE_OK;
+}
+
+CURLSHcode
+Curl_share_unlock(struct SessionHandle *data, curl_lock_data type)
+{
+ struct Curl_share *share = data->share;
+
+ if(share == NULL)
+ return CURLSHE_INVALID;
+
+ if(share->specifier & (1<<type)) {
+ if(share->unlockfunc) /* only call this if set! */
+ share->unlockfunc (data, type, share->clientdata);
+ }
+
+ return CURLSHE_OK;
+}
diff --git a/libs/libcurl/src/share.h b/libs/libcurl/src/share.h
new file mode 100644
index 0000000000..9a5128e931
--- /dev/null
+++ b/libs/libcurl/src/share.h
@@ -0,0 +1,61 @@
+#ifndef HEADER_CURL_SHARE_H
+#define HEADER_CURL_SHARE_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 <curl/curl.h>
+#include "cookie.h"
+#include "urldata.h"
+
+/* SalfordC says "A structure member may not be volatile". Hence:
+ */
+#ifdef __SALFORDC__
+#define CURL_VOLATILE
+#else
+#define CURL_VOLATILE volatile
+#endif
+
+/* this struct is libcurl-private, don't export details */
+struct Curl_share {
+ unsigned int specifier;
+ CURL_VOLATILE unsigned int dirty;
+
+ curl_lock_function lockfunc;
+ curl_unlock_function unlockfunc;
+ void *clientdata;
+
+ struct curl_hash *hostcache;
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ struct CookieInfo *cookies;
+#endif
+
+ struct curl_ssl_session *sslsession;
+ size_t max_ssl_sessions;
+ long sessionage;
+};
+
+CURLSHcode Curl_share_lock (struct SessionHandle *, curl_lock_data,
+ curl_lock_access);
+CURLSHcode Curl_share_unlock (struct SessionHandle *, curl_lock_data);
+
+#endif /* HEADER_CURL_SHARE_H */
diff --git a/libs/libcurl/src/slist.c b/libs/libcurl/src/slist.c
new file mode 100644
index 0000000000..3cac6ca21c
--- /dev/null
+++ b/libs/libcurl/src/slist.c
@@ -0,0 +1,143 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "curl_memory.h"
+#include "slist.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* returns last node in linked list */
+static struct curl_slist *slist_get_last(struct curl_slist *list)
+{
+ struct curl_slist *item;
+
+ /* if caller passed us a NULL, return now */
+ if(!list)
+ return NULL;
+
+ /* loop through to find the last item */
+ item = list;
+ while(item->next) {
+ item = item->next;
+ }
+ return item;
+}
+
+/*
+ * Curl_slist_append_nodup() appends a string to the linked list. Rather than
+ * copying the string in dynamic storage, it takes its ownership. The string
+ * should have been malloc()ated. Curl_slist_append_nodup always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function.
+ * If an error occurs, NULL is returned and the string argument is NOT
+ * released.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list, char *data)
+{
+ struct curl_slist *last;
+ struct curl_slist *new_item;
+
+ DEBUGASSERT(data);
+
+ new_item = malloc(sizeof(struct curl_slist));
+ if(!new_item)
+ return NULL;
+
+ new_item->next = NULL;
+ new_item->data = data;
+
+ /* if this is the first item, then new_item *is* the list */
+ if(!list)
+ return new_item;
+
+ last = slist_get_last(list);
+ last->next = new_item;
+ return list;
+}
+
+/*
+ * curl_slist_append() appends a string to the linked list. It always returns
+ * the address of the first record, so that you can use this function as an
+ * initialization function as well as an append function. If you find this
+ * bothersome, then simply create a separate _init function and call it
+ * appropriately from within the program.
+ */
+struct curl_slist *curl_slist_append(struct curl_slist *list,
+ const char *data)
+{
+ char *dupdata = strdup(data);
+
+ if(!dupdata)
+ return NULL;
+
+ list = Curl_slist_append_nodup(list, dupdata);
+ if(!list)
+ free(dupdata);
+
+ return list;
+}
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist)
+{
+ struct curl_slist *outlist = NULL;
+ struct curl_slist *tmp;
+
+ while(inlist) {
+ tmp = curl_slist_append(outlist, inlist->data);
+
+ if(!tmp) {
+ curl_slist_free_all(outlist);
+ return NULL;
+ }
+
+ outlist = tmp;
+ inlist = inlist->next;
+ }
+ return outlist;
+}
+
+/* be nice and clean up resources */
+void curl_slist_free_all(struct curl_slist *list)
+{
+ struct curl_slist *next;
+ struct curl_slist *item;
+
+ if(!list)
+ return;
+
+ item = list;
+ do {
+ next = item->next;
+ Curl_safefree(item->data);
+ free(item);
+ item = next;
+ } while(next);
+}
+
diff --git a/libs/libcurl/src/slist.h b/libs/libcurl/src/slist.h
new file mode 100644
index 0000000000..ea7dcc48b6
--- /dev/null
+++ b/libs/libcurl/src/slist.h
@@ -0,0 +1,40 @@
+#ifndef HEADER_CURL_SLIST_H
+#define HEADER_CURL_SLIST_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.
+ *
+ ***************************************************************************/
+
+/*
+ * Curl_slist_duplicate() duplicates a linked list. It always returns the
+ * address of the first record of the cloned list or NULL in case of an
+ * error (or if the input list was NULL).
+ */
+struct curl_slist *Curl_slist_duplicate(struct curl_slist *inlist);
+
+/*
+ * Curl_slist_append_nodup() takes ownership of the given string and appends
+ * it to the list.
+ */
+struct curl_slist *Curl_slist_append_nodup(struct curl_slist *list,
+ char *data);
+
+#endif /* HEADER_CURL_SLIST_H */
+
diff --git a/libs/libcurl/src/smtp.c b/libs/libcurl/src/smtp.c
new file mode 100644
index 0000000000..9626a30d83
--- /dev/null
+++ b/libs/libcurl/src/smtp.c
@@ -0,0 +1,1921 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ * RFC1870 SMTP Service Extension for Message Size
+ * RFC2195 CRAM-MD5 authentication
+ * RFC2831 DIGEST-MD5 authentication
+ * RFC3207 SMTP over TLS
+ * RFC4422 Simple Authentication and Security Layer (SASL)
+ * RFC4616 PLAIN authentication
+ * RFC4954 SMTP Authentication
+ * RFC5321 SMTP protocol
+ * RFC6749 OAuth 2.0 Authorization Framework
+ * Draft SMTP URL Interface
+ *
+ ***************************************************************************/
+
+#include "curl_setup.h"
+
+#ifndef CURL_DISABLE_SMTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "if2ip.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "socks.h"
+#include "smtp.h"
+
+#include "strtoofft.h"
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "select.h"
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "curl_gethostname.h"
+#include "curl_sasl.h"
+#include "warnless.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"
+
+/* Local API functions */
+static CURLcode smtp_regular_transfer(struct connectdata *conn, bool *done);
+static CURLcode smtp_do(struct connectdata *conn, bool *done);
+static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+ bool premature);
+static CURLcode smtp_connect(struct connectdata *conn, bool *done);
+static CURLcode smtp_disconnect(struct connectdata *conn, bool dead);
+static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done);
+static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done);
+static CURLcode smtp_setup_connection(struct connectdata *conn);
+static CURLcode smtp_parse_url_options(struct connectdata *conn);
+static CURLcode smtp_parse_url_path(struct connectdata *conn);
+
+/*
+ * SMTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtp = {
+ "SMTP", /* scheme */
+ smtp_setup_connection, /* setup_connection */
+ smtp_do, /* do_it */
+ smtp_done, /* done */
+ ZERO_NULL, /* do_more */
+ smtp_connect, /* connect_it */
+ smtp_multi_statemach, /* connecting */
+ smtp_doing, /* doing */
+ smtp_getsock, /* proto_getsock */
+ smtp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smtp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTP, /* defport */
+ CURLPROTO_SMTP, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_NOURLQUERY /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * SMTPS protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_smtps = {
+ "SMTPS", /* scheme */
+ smtp_setup_connection, /* setup_connection */
+ smtp_do, /* do_it */
+ smtp_done, /* done */
+ ZERO_NULL, /* do_more */
+ smtp_connect, /* connect_it */
+ smtp_multi_statemach, /* connecting */
+ smtp_doing, /* doing */
+ smtp_getsock, /* proto_getsock */
+ smtp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ smtp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTPS, /* defport */
+ CURLPROTO_SMTP | CURLPROTO_SMTPS, /* protocol */
+ PROTOPT_CLOSEACTION | PROTOPT_SSL
+ | PROTOPT_NOURLQUERY /* flags */
+};
+#endif
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * HTTP-proxyed SMTP protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtp_proxy = {
+ "SMTP", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTP, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+#ifdef USE_SSL
+/*
+ * HTTP-proxyed SMTPS protocol handler.
+ */
+
+static const struct Curl_handler Curl_handler_smtps_proxy = {
+ "SMTPS", /* scheme */
+ Curl_http_setup_conn, /* setup_connection */
+ Curl_http, /* do_it */
+ Curl_http_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SMTPS, /* defport */
+ CURLPROTO_HTTP, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+#endif
+#endif
+
+#ifdef USE_SSL
+static void smtp_to_smtps(struct connectdata *conn)
+{
+ conn->handler = &Curl_handler_smtps;
+}
+#else
+#define smtp_to_smtps(x) Curl_nop_stmt
+#endif
+
+/***********************************************************************
+ *
+ * pop3_endofresp()
+ *
+ * Checks for an ending SMTP status code at the start of the given string, but
+ * also detects various capabilities from the EHLO response including the
+ * supported authentication mechanisms.
+ */
+static bool smtp_endofresp(struct connectdata *conn, char *line, size_t len,
+ int *resp)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ bool result = FALSE;
+ size_t wordlen;
+
+ if(len < 4 || !ISDIGIT(line[0]) || !ISDIGIT(line[1]) || !ISDIGIT(line[2]))
+ return FALSE; /* Nothing for us */
+
+ /* Do we have a command response? */
+ result = (line[3] == ' ') ? TRUE : FALSE;
+ if(result)
+ *resp = curlx_sltosi(strtol(line, NULL, 10));
+
+ /* Are we processing EHLO command data? */
+ if(smtpc->state == SMTP_EHLO && (!result || (result && *resp/100 == 2))) {
+ line += 4;
+ len -= 4;
+
+ /* Does the server support the STARTTLS capability? */
+ if(len >= 8 && !memcmp(line, "STARTTLS", 8))
+ smtpc->tls_supported = TRUE;
+
+ /* Does the server support the SIZE capability? */
+ else if(len >= 4 && !memcmp(line, "SIZE", 4))
+ smtpc->size_supported = TRUE;
+
+ /* Do we have the authentication mechanism list? */
+ else if(len >= 5 && !memcmp(line, "AUTH ", 5)) {
+ line += 5;
+ len -= 5;
+
+ /* Loop through the data line */
+ for(;;) {
+ while(len &&
+ (*line == ' ' || *line == '\t' ||
+ *line == '\r' || *line == '\n')) {
+
+ line++;
+ len--;
+ }
+
+ if(!len)
+ break;
+
+ /* Extract the word */
+ for(wordlen = 0; wordlen < len && line[wordlen] != ' ' &&
+ line[wordlen] != '\t' && line[wordlen] != '\r' &&
+ line[wordlen] != '\n';)
+ wordlen++;
+
+ /* Test the word for a matching authentication mechanism */
+ if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_LOGIN))
+ smtpc->authmechs |= SASL_MECH_LOGIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_PLAIN))
+ smtpc->authmechs |= SASL_MECH_PLAIN;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_CRAM_MD5))
+ smtpc->authmechs |= SASL_MECH_CRAM_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_DIGEST_MD5))
+ smtpc->authmechs |= SASL_MECH_DIGEST_MD5;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_GSSAPI))
+ smtpc->authmechs |= SASL_MECH_GSSAPI;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_EXTERNAL))
+ smtpc->authmechs |= SASL_MECH_EXTERNAL;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_NTLM))
+ smtpc->authmechs |= SASL_MECH_NTLM;
+ else if(sasl_mech_equal(line, wordlen, SASL_MECH_STRING_XOAUTH2))
+ smtpc->authmechs |= SASL_MECH_XOAUTH2;
+
+ line += wordlen;
+ len -= wordlen;
+ }
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * state()
+ *
+ * This is the ONLY way to change SMTP state!
+ */
+static void state(struct connectdata *conn, smtpstate newstate)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "STOP",
+ "SERVERGREET",
+ "EHLO",
+ "HELO",
+ "STARTTLS",
+ "UPGRADETLS",
+ "AUTH_PLAIN",
+ "AUTH_LOGIN",
+ "AUTH_LOGIN_PASSWD",
+ "AUTH_CRAMMD5",
+ "AUTH_DIGESTMD5",
+ "AUTH_DIGESTMD5_RESP",
+ "AUTH_NTLM",
+ "AUTH_NTLM_TYPE2MSG",
+ "AUTH_XOAUTH2",
+ "AUTH_FINAL",
+ "MAIL",
+ "RCPT",
+ "DATA",
+ "POSTDATA",
+ "QUIT",
+ /* LAST */
+ };
+
+ if(smtpc->state != newstate)
+ infof(conn->data, "SMTP %p state change from %s to %s\n",
+ (void *)smtpc, names[smtpc->state], names[newstate]);
+#endif
+
+ smtpc->state = newstate;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_ehlo()
+ *
+ * Sends the EHLO command to not only initialise communication with the ESMTP
+ * server but to also obtain a list of server side supported capabilities.
+ */
+static CURLcode smtp_perform_ehlo(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ smtpc->authmechs = 0; /* No known authentication mechanisms yet */
+ smtpc->authused = 0; /* Clear the authentication mechanism used
+ for esmtp connections */
+ smtpc->tls_supported = FALSE; /* Clear the TLS capability */
+
+ /* Send the EHLO command */
+ result = Curl_pp_sendf(&smtpc->pp, "EHLO %s", smtpc->domain);
+
+ if(!result)
+ state(conn, SMTP_EHLO);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_helo()
+ *
+ * Sends the HELO command to initialise communication with the SMTP server.
+ */
+static CURLcode smtp_perform_helo(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ smtpc->authused = 0; /* No authentication mechanism used in smtp
+ connections */
+
+ /* Send the HELO command */
+ result = Curl_pp_sendf(&smtpc->pp, "HELO %s", smtpc->domain);
+
+ if(!result)
+ state(conn, SMTP_HELO);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_starttls()
+ *
+ * Sends the STLS command to start the upgrade to TLS.
+ */
+static CURLcode smtp_perform_starttls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the STARTTLS command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "STARTTLS");
+
+ if(!result)
+ state(conn, SMTP_STARTTLS);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_upgrade_tls()
+ *
+ * Performs the upgrade to TLS.
+ */
+static CURLcode smtp_perform_upgrade_tls(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ /* Start the SSL connection */
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
+
+ if(!result) {
+ if(smtpc->state != SMTP_UPGRADETLS)
+ state(conn, SMTP_UPGRADETLS);
+
+ if(smtpc->ssldone) {
+ smtp_to_smtps(conn);
+ result = smtp_perform_ehlo(conn);
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_authenticate()
+ *
+ * Sends an AUTH command allowing the client to login with the appropriate
+ * SASL authentication mechanism.
+ */
+static CURLcode smtp_perform_authenticate(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *mech = NULL;
+ char *initresp = NULL;
+ size_t len = 0;
+ smtpstate state1 = SMTP_STOP;
+ smtpstate state2 = SMTP_STOP;
+
+ /* Check we have a username and password to authenticate with and end the
+ connect phase if we don't */
+ if(!conn->bits.user_passwd) {
+ state(conn, SMTP_STOP);
+
+ return result;
+ }
+
+ /* Calculate the supported authentication mechanism, by decreasing order of
+ security, as well as the initial response where appropriate */
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ if((smtpc->authmechs & SASL_MECH_DIGEST_MD5) &&
+ (smtpc->prefmech & SASL_MECH_DIGEST_MD5)) {
+ mech = SASL_MECH_STRING_DIGEST_MD5;
+ state1 = SMTP_AUTH_DIGESTMD5;
+ smtpc->authused = SASL_MECH_DIGEST_MD5;
+ }
+ else if((smtpc->authmechs & SASL_MECH_CRAM_MD5) &&
+ (smtpc->prefmech & SASL_MECH_CRAM_MD5)) {
+ mech = SASL_MECH_STRING_CRAM_MD5;
+ state1 = SMTP_AUTH_CRAMMD5;
+ smtpc->authused = SASL_MECH_CRAM_MD5;
+ }
+ else
+#endif
+#ifdef USE_NTLM
+ if((smtpc->authmechs & SASL_MECH_NTLM) &&
+ (smtpc->prefmech & SASL_MECH_NTLM)) {
+ mech = SASL_MECH_STRING_NTLM;
+ state1 = SMTP_AUTH_NTLM;
+ state2 = SMTP_AUTH_NTLM_TYPE2MSG;
+ smtpc->authused = SASL_MECH_NTLM;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &initresp, &len);
+ }
+ else
+#endif
+ if(((smtpc->authmechs & SASL_MECH_XOAUTH2) &&
+ (smtpc->prefmech & SASL_MECH_XOAUTH2) &&
+ (smtpc->prefmech != SASL_AUTH_ANY)) || conn->xoauth2_bearer) {
+ mech = SASL_MECH_STRING_XOAUTH2;
+ state1 = SMTP_AUTH_XOAUTH2;
+ state2 = SMTP_AUTH_FINAL;
+ smtpc->authused = SASL_MECH_XOAUTH2;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &initresp, &len);
+ }
+ else if((smtpc->authmechs & SASL_MECH_LOGIN) &&
+ (smtpc->prefmech & SASL_MECH_LOGIN)) {
+ mech = SASL_MECH_STRING_LOGIN;
+ state1 = SMTP_AUTH_LOGIN;
+ state2 = SMTP_AUTH_LOGIN_PASSWD;
+ smtpc->authused = SASL_MECH_LOGIN;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_login_message(conn->data, conn->user,
+ &initresp, &len);
+ }
+ else if((smtpc->authmechs & SASL_MECH_PLAIN) &&
+ (smtpc->prefmech & SASL_MECH_PLAIN)) {
+ mech = SASL_MECH_STRING_PLAIN;
+ state1 = SMTP_AUTH_PLAIN;
+ state2 = SMTP_AUTH_FINAL;
+ smtpc->authused = SASL_MECH_PLAIN;
+
+ if(data->set.sasl_ir)
+ result = Curl_sasl_create_plain_message(conn->data, conn->user,
+ conn->passwd, &initresp, &len);
+ }
+
+ if(!result) {
+ if(mech) {
+ /* Perform SASL based authentication */
+ if(initresp &&
+ 8 + strlen(mech) + len <= 512) { /* AUTH <mech> ...<crlf> */
+ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s %s", mech, initresp);
+
+ if(!result)
+ state(conn, state2);
+ }
+ else {
+ result = Curl_pp_sendf(&smtpc->pp, "AUTH %s", mech);
+
+ if(!result)
+ state(conn, state1);
+ }
+
+ Curl_safefree(initresp);
+ }
+ else {
+ /* Other mechanisms not supported */
+ infof(conn->data, "No known authentication mechanisms supported!\n");
+ result = CURLE_LOGIN_DENIED;
+ }
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_mail()
+ *
+ * Sends an MAIL command to initiate the upload of a message.
+ */
+static CURLcode smtp_perform_mail(struct connectdata *conn)
+{
+ char *from = NULL;
+ char *auth = NULL;
+ char *size = NULL;
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ /* Calculate the FROM parameter */
+ if(!data->set.str[STRING_MAIL_FROM])
+ /* Null reverse-path, RFC-5321, sect. 3.6.3 */
+ from = strdup("<>");
+ else if(data->set.str[STRING_MAIL_FROM][0] == '<')
+ from = aprintf("%s", data->set.str[STRING_MAIL_FROM]);
+ else
+ from = aprintf("<%s>", data->set.str[STRING_MAIL_FROM]);
+
+ if(!from)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Calculate the optional AUTH parameter */
+ if(data->set.str[STRING_MAIL_AUTH] && conn->proto.smtpc.authused) {
+ if(data->set.str[STRING_MAIL_AUTH][0] != '\0')
+ auth = aprintf("%s", data->set.str[STRING_MAIL_AUTH]);
+ else
+ /* Empty AUTH, RFC-2554, sect. 5 */
+ auth = strdup("<>");
+
+ if(!auth) {
+ Curl_safefree(from);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Calculate the optional SIZE parameter */
+ if(conn->proto.smtpc.size_supported && conn->data->set.infilesize > 0) {
+ size = aprintf("%" FORMAT_OFF_T, data->set.infilesize);
+
+ if(!size) {
+ Curl_safefree(from);
+ Curl_safefree(auth);
+
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Send the MAIL command */
+ if(!auth && !size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s", from);
+ else if(auth && !size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s AUTH=%s", from, auth);
+ else if(auth && size)
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s AUTH=%s SIZE=%s", from, auth, size);
+ else
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp,
+ "MAIL FROM:%s SIZE=%s", from, size);
+
+ Curl_safefree(from);
+ Curl_safefree(auth);
+ Curl_safefree(size);
+
+ if(!result)
+ state(conn, SMTP_MAIL);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_rcpt_to()
+ *
+ * Sends a RCPT TO command for a given recipient as part of the message upload
+ * process.
+ */
+static CURLcode smtp_perform_rcpt_to(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ /* Send the RCPT TO command */
+ if(smtp->rcpt) {
+ if(smtp->rcpt->data[0] == '<')
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:%s",
+ smtp->rcpt->data);
+ else
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "RCPT TO:<%s>",
+ smtp->rcpt->data);
+ if(!result)
+ state(conn, SMTP_RCPT);
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform_quit()
+ *
+ * Performs the quit action prior to sclose() being called.
+ */
+static CURLcode smtp_perform_quit(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+ /* Send the QUIT command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "QUIT");
+
+ if(!result)
+ state(conn, SMTP_QUIT);
+
+ return result;
+}
+
+/* For the initial server greeting */
+static CURLcode smtp_state_servergreet_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "Got unexpected smtp-server response: %d", smtpcode);
+ result = CURLE_FTP_WEIRD_SERVER_REPLY;
+ }
+ else
+ result = smtp_perform_ehlo(conn);
+
+ return result;
+}
+
+/* For STARTTLS responses */
+static CURLcode smtp_state_starttls_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 220) {
+ if(data->set.use_ssl != CURLUSESSL_TRY) {
+ failf(data, "STARTTLS denied. %c", smtpcode);
+ result = CURLE_USE_SSL_FAILED;
+ }
+ else
+ result = smtp_perform_authenticate(conn);
+ }
+ else
+ result = smtp_perform_upgrade_tls(conn);
+
+ return result;
+}
+
+/* For EHLO responses */
+static CURLcode smtp_state_ehlo_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ if((data->set.use_ssl <= CURLUSESSL_TRY || conn->ssl[FIRSTSOCKET].use) &&
+ !conn->bits.user_passwd)
+ result = smtp_perform_helo(conn);
+ else {
+ failf(data, "Remote access denied: %d", smtpcode);
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ }
+ }
+ else if(data->set.use_ssl && !conn->ssl[FIRSTSOCKET].use) {
+ /* We don't have a SSL/TLS connection yet, but SSL is requested */
+ if(smtpc->tls_supported)
+ /* Switch to TLS connection now */
+ result = smtp_perform_starttls(conn);
+ else if(data->set.use_ssl == CURLUSESSL_TRY)
+ /* Fallback and carry on with authentication */
+ result = smtp_perform_authenticate(conn);
+ else {
+ failf(data, "STARTTLS not supported.");
+ result = CURLE_USE_SSL_FAILED;
+ }
+ }
+ else
+ result = smtp_perform_authenticate(conn);
+
+ return result;
+}
+
+/* For HELO responses */
+static CURLcode smtp_state_helo_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "Remote access denied: %d", smtpcode);
+ result = CURLE_REMOTE_ACCESS_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, SMTP_STOP);
+
+ return result;
+}
+
+/* For AUTH PLAIN (without initial response) responses */
+static CURLcode smtp_state_auth_plain_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *plainauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_plain_message(conn->data, conn->user,
+ conn->passwd, &plainauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(plainauth) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", plainauth);
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ Curl_safefree(plainauth);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTH LOGIN (without initial response) responses */
+static CURLcode smtp_state_auth_login_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authuser = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the user message */
+ result = Curl_sasl_create_login_message(conn->data, conn->user,
+ &authuser, &len);
+
+ /* Send the user */
+ if(!result) {
+ if(authuser) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authuser);
+
+ if(!result)
+ state(conn, SMTP_AUTH_LOGIN_PASSWD);
+ }
+
+ Curl_safefree(authuser);
+ }
+ }
+
+ return result;
+}
+
+/* For AUTH LOGIN user entry responses */
+static CURLcode smtp_state_auth_login_password_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *authpasswd = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the password message */
+ result = Curl_sasl_create_login_message(conn->data, conn->passwd,
+ &authpasswd, &len);
+
+ /* Send the password */
+ if(!result) {
+ if(authpasswd) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", authpasswd);
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ Curl_safefree(authpasswd);
+ }
+ }
+
+ return result;
+}
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+/* For AUTH CRAM-MD5 responses */
+static CURLcode smtp_state_auth_cram_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Terminate the challenge */
+ if(*chlg64 != '=') {
+ for(len = strlen(chlg64); len--;)
+ if(chlg64[len] != '\r' && chlg64[len] != '\n' && chlg64[len] != ' ' &&
+ chlg64[len] != '\t')
+ break;
+
+ if(++len) {
+ chlg64[len] = '\0';
+ }
+ }
+
+ /* Create the response message */
+ result = Curl_sasl_create_cram_md5_message(data, chlg64, conn->user,
+ conn->passwd, &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTH DIGEST-MD5 challenge responses */
+static CURLcode smtp_state_auth_digest_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *chlg64 = data->state.buffer;
+ size_t len = 0;
+ char *rplyb64 = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ return CURLE_LOGIN_DENIED;
+ }
+
+ /* Get the challenge */
+ for(chlg64 += 4; *chlg64 == ' ' || *chlg64 == '\t'; chlg64++)
+ ;
+
+ /* Create the response message */
+ result = Curl_sasl_create_digest_md5_message(data, chlg64, conn->user,
+ conn->passwd, "smtp",
+ &rplyb64, &len);
+
+ /* Send the response */
+ if(!result) {
+ if(rplyb64) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", rplyb64);
+
+ if(!result)
+ state(conn, SMTP_AUTH_DIGESTMD5_RESP);
+ }
+
+ Curl_safefree(rplyb64);
+ }
+
+ return result;
+}
+
+/* For AUTH DIGEST-MD5 challenge-response responses */
+static CURLcode smtp_state_auth_digest_resp_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Authentication failed: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Send an empty response */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "");
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ return result;
+}
+
+#endif
+
+#ifdef USE_NTLM
+/* For AUTH NTLM (without initial response) responses */
+static CURLcode smtp_state_auth_ntlm_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *type1msg = NULL;
+ size_t len = 0;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-1 message */
+ result = Curl_sasl_create_ntlm_type1_message(conn->user, conn->passwd,
+ &conn->ntlm,
+ &type1msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type1msg) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type1msg);
+
+ if(!result)
+ state(conn, SMTP_AUTH_NTLM_TYPE2MSG);
+ }
+
+ Curl_safefree(type1msg);
+ }
+ }
+
+ return result;
+}
+
+/* For NTLM type-2 responses (sent in reponse to our type-1 message) */
+static CURLcode smtp_state_auth_ntlm_type2msg_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ char *type3msg = NULL;
+ size_t len = 0;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the type-3 message */
+ result = Curl_sasl_create_ntlm_type3_message(data,
+ data->state.buffer + 4,
+ conn->user, conn->passwd,
+ &conn->ntlm,
+ &type3msg, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(type3msg) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", type3msg);
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ Curl_safefree(type3msg);
+ }
+ }
+
+ return result;
+}
+#endif
+
+/* For AUTH XOAUTH2 (without initial response) responses */
+static CURLcode smtp_state_auth_xoauth2_resp(struct connectdata *conn,
+ int smtpcode, smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ size_t len = 0;
+ char *xoauth = NULL;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 334) {
+ failf(data, "Access denied: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else {
+ /* Create the authorisation message */
+ result = Curl_sasl_create_xoauth2_message(conn->data, conn->user,
+ conn->xoauth2_bearer,
+ &xoauth, &len);
+
+ /* Send the message */
+ if(!result) {
+ if(xoauth) {
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", xoauth);
+
+ if(!result)
+ state(conn, SMTP_AUTH_FINAL);
+ }
+
+ Curl_safefree(xoauth);
+ }
+ }
+
+ return result;
+}
+
+/* For the final responses to the AUTH sequence */
+static CURLcode smtp_state_auth_final_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 235) {
+ failf(data, "Authentication failed: %d", smtpcode);
+ result = CURLE_LOGIN_DENIED;
+ }
+ else
+ /* End of connect phase */
+ state(conn, SMTP_STOP);
+
+ return result;
+}
+
+/* For MAIL responses */
+static CURLcode smtp_state_mail_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "MAIL failed: %d", smtpcode);
+ result = CURLE_SEND_ERROR;
+ state(conn, SMTP_STOP);
+ }
+ else {
+ smtp->rcpt = data->set.mail_rcpt;
+
+ result = smtp_perform_rcpt_to(conn);
+ }
+
+ return result;
+}
+
+/* For RCPT responses */
+static CURLcode smtp_state_rcpt_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode/100 != 2) {
+ failf(data, "RCPT failed: %d", smtpcode);
+ result = CURLE_SEND_ERROR;
+ state(conn, SMTP_STOP);
+ }
+ else {
+ if(smtp->rcpt) {
+ smtp->rcpt = smtp->rcpt->next;
+ result = smtp_perform_rcpt_to(conn);
+
+ /* If we failed or still are sending RCPT data then return */
+ if(result || smtp->rcpt)
+ return result;
+ }
+
+ /* Send the DATA command */
+ result = Curl_pp_sendf(&conn->proto.smtpc.pp, "%s", "DATA");
+
+ if(!result)
+ state(conn, SMTP_DATA);
+ }
+
+ return result;
+}
+
+/* For DATA response */
+static CURLcode smtp_state_data_resp(struct connectdata *conn, int smtpcode,
+ smtpstate instate)
+{
+ struct SessionHandle *data = conn->data;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 354) {
+ state(conn, SMTP_STOP);
+ return CURLE_SEND_ERROR;
+ }
+
+ /* Set the progress upload size */
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+
+ /* SMTP upload */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* End of DO phase */
+ state(conn, SMTP_STOP);
+
+ return CURLE_OK;
+}
+
+/* For POSTDATA responses, which are received after the entire DATA
+ part has been sent to the server */
+static CURLcode smtp_state_postdata_resp(struct connectdata *conn,
+ int smtpcode,
+ smtpstate instate)
+{
+ CURLcode result = CURLE_OK;
+
+ (void)instate; /* no use for this yet */
+
+ if(smtpcode != 250)
+ result = CURLE_RECV_ERROR;
+
+ /* End of DONE phase */
+ state(conn, SMTP_STOP);
+
+ return result;
+}
+
+static CURLcode smtp_statemach_act(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ struct SessionHandle *data = conn->data;
+ int smtpcode;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct pingpong *pp = &smtpc->pp;
+ size_t nread = 0;
+
+ /* Busy upgrading the connection; right now all I/O is SSL/TLS, not SMTP */
+ if(smtpc->state == SMTP_UPGRADETLS)
+ return smtp_perform_upgrade_tls(conn);
+
+ /* Flush any data that needs to be sent */
+ if(pp->sendleft)
+ return Curl_pp_flushsend(pp);
+
+ /* Read the response from the server */
+ result = Curl_pp_readresp(sock, pp, &smtpcode, &nread);
+ if(result)
+ return result;
+
+ /* Store the latest response for later retrieval */
+ if(smtpc->state != SMTP_QUIT)
+ data->info.httpcode = smtpcode;
+
+ if(smtpcode) {
+ /* We have now received a full SMTP server response */
+ switch(smtpc->state) {
+ case SMTP_SERVERGREET:
+ result = smtp_state_servergreet_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_EHLO:
+ result = smtp_state_ehlo_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_HELO:
+ result = smtp_state_helo_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_STARTTLS:
+ result = smtp_state_starttls_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_PLAIN:
+ result = smtp_state_auth_plain_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_LOGIN:
+ result = smtp_state_auth_login_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_LOGIN_PASSWD:
+ result = smtp_state_auth_login_password_resp(conn, smtpcode,
+ smtpc->state);
+ break;
+
+#ifndef CURL_DISABLE_CRYPTO_AUTH
+ case SMTP_AUTH_CRAMMD5:
+ result = smtp_state_auth_cram_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_DIGESTMD5:
+ result = smtp_state_auth_digest_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_DIGESTMD5_RESP:
+ result = smtp_state_auth_digest_resp_resp(conn, smtpcode, smtpc->state);
+ break;
+#endif
+
+#ifdef USE_NTLM
+ case SMTP_AUTH_NTLM:
+ result = smtp_state_auth_ntlm_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_NTLM_TYPE2MSG:
+ result = smtp_state_auth_ntlm_type2msg_resp(conn, smtpcode,
+ smtpc->state);
+ break;
+#endif
+
+ case SMTP_AUTH_XOAUTH2:
+ result = smtp_state_auth_xoauth2_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_AUTH_FINAL:
+ result = smtp_state_auth_final_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_MAIL:
+ result = smtp_state_mail_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_RCPT:
+ result = smtp_state_rcpt_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_DATA:
+ result = smtp_state_data_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_POSTDATA:
+ result = smtp_state_postdata_resp(conn, smtpcode, smtpc->state);
+ break;
+
+ case SMTP_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ state(conn, SMTP_STOP);
+ break;
+ }
+ }
+
+ return result;
+}
+
+/* Called repeatedly until done from multi.c */
+static CURLcode smtp_multi_statemach(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ if((conn->handler->flags & PROTOPT_SSL) && !smtpc->ssldone) {
+ result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &smtpc->ssldone);
+ if(result || !smtpc->ssldone)
+ return result;
+ }
+
+ result = Curl_pp_statemach(&smtpc->pp, FALSE);
+ *done = (smtpc->state == SMTP_STOP) ? TRUE : FALSE;
+
+ return result;
+}
+
+static CURLcode smtp_block_statemach(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ while(smtpc->state != SMTP_STOP && !result)
+ result = Curl_pp_statemach(&smtpc->pp, TRUE);
+
+ return result;
+}
+
+/* Allocate and initialize the SMTP struct for the current SessionHandle if
+ required */
+static CURLcode smtp_init(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp;
+
+ smtp = data->req.protop = calloc(sizeof(struct SMTP), 1);
+ if(!smtp)
+ result = CURLE_OUT_OF_MEMORY;
+
+ return result;
+}
+
+/* For the SMTP "protocol connect" and "doing" phases only */
+static int smtp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ return Curl_pp_getsock(&conn->proto.smtpc.pp, socks, numsocks);
+}
+
+/***********************************************************************
+ *
+ * smtp_connect()
+ *
+ * This function should do everything that is to be considered a part of
+ * the connection phase.
+ *
+ * The variable pointed to by 'done' will be TRUE if the protocol-layer
+ * connect phase is done when this function returns, or FALSE if not.
+ */
+static CURLcode smtp_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ struct pingpong *pp = &smtpc->pp;
+
+ *done = FALSE; /* default to not done yet */
+
+ /* We always support persistent connections in SMTP */
+ conn->bits.close = FALSE;
+
+ /* Set the default response time-out */
+ pp->response_time = RESP_TIMEOUT;
+ pp->statemach_act = smtp_statemach_act;
+ pp->endofresp = smtp_endofresp;
+ pp->conn = conn;
+
+ /* Set the default preferred authentication mechanism */
+ smtpc->prefmech = SASL_AUTH_ANY;
+
+ /* Initialise the pingpong layer */
+ Curl_pp_init(pp);
+
+ /* Parse the URL options */
+ result = smtp_parse_url_options(conn);
+ if(result)
+ return result;
+
+ /* Parse the URL path */
+ result = smtp_parse_url_path(conn);
+ if(result)
+ return result;
+
+ /* Start off waiting for the server greeting response */
+ state(conn, SMTP_SERVERGREET);
+
+ result = smtp_multi_statemach(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_done()
+ *
+ * The DONE function. This does what needs to be done after a single DO has
+ * performed.
+ *
+ * Input argument is already checked for validity.
+ */
+static CURLcode smtp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+ struct pingpong *pp = &conn->proto.smtpc.pp;
+ const char *eob;
+ ssize_t len;
+ ssize_t bytes_written;
+
+ (void)premature;
+
+ if(!smtp)
+ /* When the easy handle is removed from the multi interface while libcurl
+ is still trying to resolve the host name, the SMTP struct is not yet
+ initialized. However, the removal action calls Curl_done() which in
+ turn calls this function, so we simply return success. */
+ return CURLE_OK;
+
+ if(status) {
+ conn->bits.close = TRUE; /* marked for closure */
+ result = status; /* use the already set error code */
+ }
+ else if(!data->set.connect_only) {
+ /* Calculate the EOB taking into account any terminating CRLF from the
+ previous line of the email or the CRLF of the DATA command when there
+ is "no mail data". RFC-5321, sect. 4.1.1.4. */
+ eob = SMTP_EOB;
+ len = SMTP_EOB_LEN;
+ if(smtp->trailing_crlf || !conn->data->set.infilesize) {
+ eob += 2;
+ len -= 2;
+ }
+
+ /* Send the end of block data */
+ result = Curl_write(conn, conn->writesockfd, eob, len, &bytes_written);
+ if(result)
+ return result;
+
+ if(bytes_written != len) {
+ /* The whole chunk was not sent so keep it around and adjust the
+ pingpong structure accordingly */
+ pp->sendthis = strdup(eob);
+ pp->sendsize = len;
+ pp->sendleft = len - bytes_written;
+ }
+ else
+ /* Successfully sent so adjust the response timeout relative to now */
+ pp->response = Curl_tvnow();
+
+ state(conn, SMTP_POSTDATA);
+
+ /* Run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the smtp_multi_statemach function but we have no general support for
+ non-blocking DONE operations, not in the multi state machine and with
+ Curl_done() invokes on several places in the code!
+ */
+ result = smtp_block_statemach(conn);
+ }
+
+ /* Clear the transfer mode for the next request */
+ smtp->transfer = FTPTRANSFER_BODY;
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_perform()
+ *
+ * This is the actual DO function for SMTP. Send a mail according to the
+ * options previously setup.
+ */
+static CURLcode smtp_perform(struct connectdata *conn, bool *connected,
+ bool *dophase_done)
+{
+ /* This is SMTP and no proxy */
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ if(conn->data->set.opt_no_body) {
+ /* Requested no body means no transfer */
+ struct SMTP *smtp = conn->data->req.protop;
+ smtp->transfer = FTPTRANSFER_INFO;
+ }
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* Start the first command in the DO phase */
+ result = smtp_perform_mail(conn);
+ if(result)
+ return result;
+
+ /* run the state-machine */
+ result = smtp_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_do()
+ *
+ * This function is registered as 'curl_do' function. It decodes the path
+ * parts etc as a wrapper to the actual DO function (smtp_perform).
+ *
+ * The input argument is already checked for validity.
+ */
+static CURLcode smtp_do(struct connectdata *conn, bool *done)
+{
+ CURLcode result = CURLE_OK;
+
+ *done = FALSE; /* default to false */
+
+ result = smtp_regular_transfer(conn, done);
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_disconnect()
+ *
+ * Disconnect from an SMTP server. Cleanup protocol-specific per-connection
+ * resources. BLOCKING.
+ */
+static CURLcode smtp_disconnect(struct connectdata *conn,
+ bool dead_connection)
+{
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+
+ /* We cannot send quit unconditionally. If this connection is stale or
+ bad in any way, sending quit and waiting around here will make the
+ disconnect wait in vain and cause more problems than we need to. */
+
+ /* The SMTP session may or may not have been allocated/setup at this
+ point! */
+ if(!dead_connection && smtpc->pp.conn)
+ if(!smtp_perform_quit(conn))
+ (void)smtp_block_statemach(conn); /* ignore errors on QUIT */
+
+ /* Disconnect from the server */
+ Curl_pp_disconnect(&smtpc->pp);
+
+ /* Cleanup the SASL module */
+ Curl_sasl_cleanup(conn, smtpc->authused);
+
+ /* Cleanup our connection based variables */
+ Curl_safefree(smtpc->domain);
+
+ return CURLE_OK;
+}
+
+/* Call this when the DO phase has completed */
+static CURLcode smtp_dophase_done(struct connectdata *conn, bool connected)
+{
+ struct SMTP *smtp = conn->data->req.protop;
+
+ (void)connected;
+
+ if(smtp->transfer != FTPTRANSFER_BODY)
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return CURLE_OK;
+}
+
+/* Called from multi.c while DOing */
+static CURLcode smtp_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = smtp_multi_statemach(conn, dophase_done);
+
+ if(result)
+ DEBUGF(infof(conn->data, "DO phase failed\n"));
+ else if(*dophase_done) {
+ result = smtp_dophase_done(conn, FALSE /* not connected */);
+
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_regular_transfer()
+ *
+ * The input argument is already checked for validity.
+ *
+ * Performs all commands done before a regular transfer between a local and a
+ * remote host.
+ */
+static CURLcode smtp_regular_transfer(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ bool connected = FALSE;
+ struct SessionHandle *data = conn->data;
+
+ /* Make sure size is unknown at this point */
+ data->req.size = -1;
+
+ /* Set the progress data */
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ /* Carry out the perform */
+ result = smtp_perform(conn, &connected, dophase_done);
+
+ /* Perform post DO phase operations if necessary */
+ if(!result && *dophase_done)
+ result = smtp_dophase_done(conn, connected);
+
+ return result;
+}
+
+static CURLcode smtp_setup_connection(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ CURLcode result;
+
+ if(conn->bits.httpproxy && !data->set.tunnel_thru_httpproxy) {
+ /* Unless we have asked to tunnel SMTP operations through the proxy, we
+ switch and use HTTP operations only */
+#ifndef CURL_DISABLE_HTTP
+ if(conn->handler == &Curl_handler_smtp)
+ conn->handler = &Curl_handler_smtp_proxy;
+ else {
+#ifdef USE_SSL
+ conn->handler = &Curl_handler_smtps_proxy;
+#else
+ failf(data, "SMTPS not supported!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+ /* set it up as a HTTP connection instead */
+ return conn->handler->setup_connection(conn);
+
+#else
+ failf(data, "SMTP over http proxy requires HTTP support built-in!");
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ }
+
+ /* Initialise the SMTP layer */
+ result = smtp_init(conn);
+ if(result)
+ return result;
+
+ data->state.path++; /* don't include the initial slash */
+
+ return CURLE_OK;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_options()
+ *
+ * Parse the URL login options.
+ */
+static CURLcode smtp_parse_url_options(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *options = conn->options;
+ const char *ptr = options;
+
+ if(options) {
+ const char *key = ptr;
+
+ while(*ptr && *ptr != '=')
+ ptr++;
+
+ if(strnequal(key, "AUTH", 4)) {
+ const char *value = ptr + 1;
+
+ if(strequal(value, "*"))
+ smtpc->prefmech = SASL_AUTH_ANY;
+ else if(strequal(value, SASL_MECH_STRING_LOGIN))
+ smtpc->prefmech = SASL_MECH_LOGIN;
+ else if(strequal(value, SASL_MECH_STRING_PLAIN))
+ smtpc->prefmech = SASL_MECH_PLAIN;
+ else if(strequal(value, SASL_MECH_STRING_CRAM_MD5))
+ smtpc->prefmech = SASL_MECH_CRAM_MD5;
+ else if(strequal(value, SASL_MECH_STRING_DIGEST_MD5))
+ smtpc->prefmech = SASL_MECH_DIGEST_MD5;
+ else if(strequal(value, SASL_MECH_STRING_GSSAPI))
+ smtpc->prefmech = SASL_MECH_GSSAPI;
+ else if(strequal(value, SASL_MECH_STRING_NTLM))
+ smtpc->prefmech = SASL_MECH_NTLM;
+ else if(strequal(value, SASL_MECH_STRING_XOAUTH2))
+ smtpc->prefmech = SASL_MECH_XOAUTH2;
+ else
+ smtpc->prefmech = SASL_AUTH_NONE;
+ }
+ else
+ result = CURLE_URL_MALFORMAT;
+ }
+
+ return result;
+}
+
+/***********************************************************************
+ *
+ * smtp_parse_url_path()
+ *
+ * Parse the URL path into separate path components.
+ */
+static CURLcode smtp_parse_url_path(struct connectdata *conn)
+{
+ /* The SMTP struct is already initialised in smtp_connect() */
+ struct SessionHandle *data = conn->data;
+ struct smtp_conn *smtpc = &conn->proto.smtpc;
+ const char *path = data->state.path;
+ char localhost[HOSTNAME_MAX + 1];
+
+ /* Calculate the path if necessary */
+ if(!*path) {
+ if(!Curl_gethostname(localhost, sizeof(localhost)))
+ path = localhost;
+ else
+ path = "localhost";
+ }
+
+ /* URL decode the path and use it as the domain in our EHLO */
+ return Curl_urldecode(conn->data, path, 0, &smtpc->domain, NULL, TRUE);
+}
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread)
+{
+ /* When sending a SMTP payload we must detect CRLF. sequences making sure
+ they are sent as CRLF.. instead, as a . on the beginning of a line will
+ be deleted by the server when not part of an EOB terminator and a
+ genuine CRLF.CRLF which isn't escaped will wrongly be detected as end of
+ data by the server
+ */
+ ssize_t i;
+ ssize_t si;
+ struct SessionHandle *data = conn->data;
+ struct SMTP *smtp = data->req.protop;
+
+ /* Do we need to allocate the scatch buffer? */
+ if(!data->state.scratch) {
+ data->state.scratch = malloc(2 * BUFSIZE);
+
+ if(!data->state.scratch) {
+ failf (data, "Failed to alloc scratch buffer!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* This loop can be improved by some kind of Boyer-Moore style of
+ approach but that is saved for later... */
+ for(i = 0, si = 0; i < nread; i++) {
+ if(SMTP_EOB[smtp->eob] == data->req.upload_fromhere[i]) {
+ smtp->eob++;
+
+ /* Is the EOB potentially the terminating CRLF? */
+ if(2 == smtp->eob || SMTP_EOB_LEN == smtp->eob)
+ smtp->trailing_crlf = TRUE;
+ else
+ smtp->trailing_crlf = FALSE;
+ }
+ else if(smtp->eob) {
+ /* A previous substring matched so output that first */
+ memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
+ si += smtp->eob;
+
+ /* Then compare the first byte */
+ if(SMTP_EOB[0] == data->req.upload_fromhere[i])
+ smtp->eob = 1;
+ else
+ smtp->eob = 0;
+
+ /* Reset the trailing CRLF flag as there was more data */
+ smtp->trailing_crlf = FALSE;
+ }
+
+ /* Do we have a match for CRLF. as per RFC-5321, sect. 4.5.2 */
+ if(SMTP_EOB_FIND_LEN == smtp->eob) {
+ /* Copy the replacement data to the target buffer */
+ memcpy(&data->state.scratch[si], SMTP_EOB_REPL, SMTP_EOB_REPL_LEN);
+ si += SMTP_EOB_REPL_LEN;
+ smtp->eob = 0;
+ }
+ else if(!smtp->eob)
+ data->state.scratch[si++] = data->req.upload_fromhere[i];
+ }
+
+ if(smtp->eob) {
+ /* A substring matched before processing ended so output that now */
+ memcpy(&data->state.scratch[si], SMTP_EOB, smtp->eob);
+ si += smtp->eob;
+ smtp->eob = 0;
+ }
+
+ if(si != nread) {
+ /* Only use the new buffer if we replaced something */
+ nread = si;
+
+ /* Upload from the new (replaced) buffer instead */
+ data->req.upload_fromhere = data->state.scratch;
+
+ /* Set the new amount too */
+ data->req.upload_present = nread;
+ }
+
+ return CURLE_OK;
+}
+
+#endif /* CURL_DISABLE_SMTP */
diff --git a/libs/libcurl/src/smtp.h b/libs/libcurl/src/smtp.h
new file mode 100644
index 0000000000..14429a5e7e
--- /dev/null
+++ b/libs/libcurl/src/smtp.h
@@ -0,0 +1,98 @@
+#ifndef HEADER_CURL_SMTP_H
+#define HEADER_CURL_SMTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009 - 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 "pingpong.h"
+
+/****************************************************************************
+ * SMTP unique setup
+ ***************************************************************************/
+typedef enum {
+ SMTP_STOP, /* do nothing state, stops the state machine */
+ SMTP_SERVERGREET, /* waiting for the initial greeting immediately after
+ a connect */
+ SMTP_EHLO,
+ SMTP_HELO,
+ SMTP_STARTTLS,
+ SMTP_UPGRADETLS, /* asynchronously upgrade the connection to SSL/TLS
+ (multi mode only) */
+ SMTP_AUTH_PLAIN,
+ SMTP_AUTH_LOGIN,
+ SMTP_AUTH_LOGIN_PASSWD,
+ SMTP_AUTH_CRAMMD5,
+ SMTP_AUTH_DIGESTMD5,
+ SMTP_AUTH_DIGESTMD5_RESP,
+ SMTP_AUTH_NTLM,
+ SMTP_AUTH_NTLM_TYPE2MSG,
+ SMTP_AUTH_XOAUTH2,
+ SMTP_AUTH_FINAL,
+ SMTP_MAIL, /* MAIL FROM */
+ SMTP_RCPT, /* RCPT TO */
+ SMTP_DATA,
+ SMTP_POSTDATA,
+ SMTP_QUIT,
+ SMTP_LAST /* never used */
+} smtpstate;
+
+/* This SMTP struct is used in the SessionHandle. All SMTP data that is
+ connection-oriented must be in smtp_conn to properly deal with the fact that
+ perhaps the SessionHandle is changed between the times the connection is
+ used. */
+struct SMTP {
+ curl_pp_transfer transfer;
+ struct curl_slist *rcpt; /* Recipient list */
+ size_t eob; /* Number of bytes of the EOB (End Of Body) that
+ have been received so far */
+ bool trailing_crlf; /* Specifies if the tailing CRLF is present */
+};
+
+/* smtp_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct smtp_conn {
+ struct pingpong pp;
+ smtpstate state; /* Always use smtp.c:state() to change state! */
+ bool ssldone; /* Is connect() over SSL done? */
+ char *domain; /* Client address/name to send in the EHLO */
+ unsigned int authmechs; /* Accepted authentication mechanisms */
+ unsigned int prefmech; /* Preferred authentication mechanism */
+ unsigned int authused; /* Auth mechanism used for the connection */
+ bool tls_supported; /* StartTLS capability supported by server */
+ bool size_supported; /* If server supports SIZE extension according to
+ RFC 1870 */
+};
+
+extern const struct Curl_handler Curl_handler_smtp;
+extern const struct Curl_handler Curl_handler_smtps;
+
+/* this is the 5-bytes End-Of-Body marker for SMTP */
+#define SMTP_EOB "\x0d\x0a\x2e\x0d\x0a"
+#define SMTP_EOB_LEN 5
+#define SMTP_EOB_FIND_LEN 3
+
+/* if found in data, replace it with this string instead */
+#define SMTP_EOB_REPL "\x0d\x0a\x2e\x2e"
+#define SMTP_EOB_REPL_LEN 4
+
+CURLcode Curl_smtp_escape_eob(struct connectdata *conn, ssize_t nread);
+
+#endif /* HEADER_CURL_SMTP_H */
diff --git a/libs/libcurl/src/sockaddr.h b/libs/libcurl/src/sockaddr.h
new file mode 100644
index 0000000000..6a2151c9d2
--- /dev/null
+++ b/libs/libcurl/src/sockaddr.h
@@ -0,0 +1,43 @@
+#ifndef HEADER_CURL_SOCKADDR_H
+#define HEADER_CURL_SOCKADDR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2009, 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"
+
+struct Curl_sockaddr_storage {
+ union {
+ struct sockaddr sa;
+ struct sockaddr_in sa_in;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 sa_in6;
+#endif
+#ifdef HAVE_STRUCT_SOCKADDR_STORAGE
+ struct sockaddr_storage sa_stor;
+#else
+ char cbuf[256]; /* this should be big enough to fit a lot */
+#endif
+ } buffer;
+};
+
+#endif /* HEADER_CURL_SOCKADDR_H */
+
diff --git a/libs/libcurl/src/socks.c b/libs/libcurl/src/socks.c
new file mode 100644
index 0000000000..b101a0de48
--- /dev/null
+++ b/libs/libcurl/src/socks.c
@@ -0,0 +1,751 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if !defined(CURL_DISABLE_PROXY)
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "strequal.h"
+#include "select.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn, /* connection data */
+ curl_socket_t sockfd, /* read from this socket */
+ char *buf, /* store read data here */
+ ssize_t buffersize, /* max amount to read */
+ ssize_t *n) /* amount bytes read */
+{
+ ssize_t nread;
+ ssize_t allread = 0;
+ int result;
+ long timeleft;
+ *n = 0;
+ for(;;) {
+ timeleft = Curl_timeleft(conn->data, NULL, TRUE);
+ if(timeleft < 0) {
+ /* we already got the timeout */
+ result = CURLE_OPERATION_TIMEDOUT;
+ break;
+ }
+ if(Curl_socket_ready(sockfd, CURL_SOCKET_BAD, timeleft) <= 0) {
+ result = ~CURLE_OK;
+ break;
+ }
+ result = Curl_read_plain(sockfd, buf, buffersize, &nread);
+ if(CURLE_AGAIN == result)
+ continue;
+ else if(result)
+ break;
+
+ if(buffersize == nread) {
+ allread += nread;
+ *n = allread;
+ result = CURLE_OK;
+ break;
+ }
+ if(!nread) {
+ result = ~CURLE_OK;
+ break;
+ }
+
+ buffersize -= nread;
+ buf += nread;
+ allread += nread;
+ }
+ return result;
+}
+
+/*
+* This function logs in to a SOCKS4 proxy and sends the specifics to the final
+* destination server.
+*
+* Reference :
+* http://socks.permeo.com/protocol/socks4.protocol
+*
+* Note :
+* Set protocol4a=true for "SOCKS 4A (Simple Extension to SOCKS 4 Protocol)"
+* Nonsupport "Identification Protocol (RFC1413)"
+*/
+CURLcode Curl_SOCKS4(const char *proxy_name,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool protocol4a)
+{
+#define SOCKS4REQLEN 262
+ unsigned char socksreq[SOCKS4REQLEN]; /* room for SOCKS4 request incl. user
+ id */
+ int result;
+ CURLcode code;
+ curl_socket_t sock = conn->sock[sockindex];
+ struct SessionHandle *data = conn->data;
+
+ if(Curl_timeleft(data, NULL, TRUE) < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ curlx_nonblock(sock, FALSE);
+
+ /*
+ * Compose socks4 request
+ *
+ * Request format
+ *
+ * +----+----+----+----+----+----+----+----+----+----+....+----+
+ * | VN | CD | DSTPORT | DSTIP | USERID |NULL|
+ * +----+----+----+----+----+----+----+----+----+----+....+----+
+ * # of bytes: 1 1 2 4 variable 1
+ */
+
+ socksreq[0] = 4; /* version (SOCKS4) */
+ socksreq[1] = 1; /* connect */
+ socksreq[2] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
+ socksreq[3] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
+
+ /* DNS resolve only for SOCKS4, not SOCKS4a */
+ if(!protocol4a) {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *hp=NULL;
+ int rc;
+
+ rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+ if(rc == CURLRESOLV_ERROR)
+ return CURLE_COULDNT_RESOLVE_PROXY;
+
+ if(rc == CURLRESOLV_PENDING)
+ /* ignores the return code, but 'dns' remains NULL on failure */
+ (void)Curl_resolver_wait_resolv(conn, &dns);
+
+ /*
+ * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
+ * returns a Curl_addrinfo pointer that may not always look the same.
+ */
+ if(dns)
+ hp=dns->addr;
+ if(hp) {
+ char buf[64];
+ unsigned short ip[4];
+ Curl_printable_address(hp, buf, sizeof(buf));
+
+ if(4 == sscanf( buf, "%hu.%hu.%hu.%hu",
+ &ip[0], &ip[1], &ip[2], &ip[3])) {
+ /* Set DSTIP */
+ socksreq[4] = (unsigned char)ip[0];
+ socksreq[5] = (unsigned char)ip[1];
+ socksreq[6] = (unsigned char)ip[2];
+ socksreq[7] = (unsigned char)ip[3];
+ }
+ else
+ hp = NULL; /* fail! */
+
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+
+ }
+ if(!hp) {
+ failf(data, "Failed to resolve \"%s\" for SOCKS4 connect.",
+ hostname);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ }
+
+ /*
+ * This is currently not supporting "Identification Protocol (RFC1413)".
+ */
+ socksreq[8] = 0; /* ensure empty userid is NUL-terminated */
+ if(proxy_name) {
+ size_t plen = strlen(proxy_name);
+ if(plen >= sizeof(socksreq) - 8) {
+ failf(data, "Too long SOCKS proxy name, can't use!\n");
+ return CURLE_COULDNT_CONNECT;
+ }
+ /* copy the proxy name WITH trailing zero */
+ memcpy(socksreq + 8, proxy_name, plen+1);
+ }
+
+ /*
+ * Make connection
+ */
+ {
+ ssize_t actualread;
+ ssize_t written;
+ ssize_t hostnamelen = 0;
+ int packetsize = 9 +
+ (int)strlen((char*)socksreq + 8); /* size including NUL */
+
+ /* If SOCKS4a, set special invalid IP address 0.0.0.x */
+ if(protocol4a) {
+ socksreq[4] = 0;
+ socksreq[5] = 0;
+ socksreq[6] = 0;
+ socksreq[7] = 1;
+ /* If still enough room in buffer, also append hostname */
+ hostnamelen = (ssize_t)strlen(hostname) + 1; /* length including NUL */
+ if(packetsize + hostnamelen <= SOCKS4REQLEN)
+ strcpy((char*)socksreq + packetsize, hostname);
+ else
+ hostnamelen = 0; /* Flag: hostname did not fit in buffer */
+ }
+
+ /* Send request */
+ code = Curl_write_plain(conn, sock, (char *)socksreq,
+ packetsize + hostnamelen,
+ &written);
+ if((code != CURLE_OK) || (written != packetsize + hostnamelen)) {
+ failf(data, "Failed to send SOCKS4 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(protocol4a && hostnamelen == 0) {
+ /* SOCKS4a with very long hostname - send that name separately */
+ hostnamelen = (ssize_t)strlen(hostname) + 1;
+ code = Curl_write_plain(conn, sock, (char *)hostname, hostnamelen,
+ &written);
+ if((code != CURLE_OK) || (written != hostnamelen)) {
+ failf(data, "Failed to send SOCKS4 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ packetsize = 8; /* receive data size */
+
+ /* Receive response */
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, packetsize,
+ &actualread);
+ if((result != CURLE_OK) || (actualread != packetsize)) {
+ failf(data, "Failed to receive SOCKS4 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /*
+ * Response format
+ *
+ * +----+----+----+----+----+----+----+----+
+ * | VN | CD | DSTPORT | DSTIP |
+ * +----+----+----+----+----+----+----+----+
+ * # of bytes: 1 1 2 4
+ *
+ * VN is the version of the reply code and should be 0. CD is the result
+ * code with one of the following values:
+ *
+ * 90: request granted
+ * 91: request rejected or failed
+ * 92: request rejected because SOCKS server cannot connect to
+ * identd on the client
+ * 93: request rejected because the client program and identd
+ * report different user-ids
+ */
+
+ /* wrong version ? */
+ if(socksreq[0] != 0) {
+ failf(data,
+ "SOCKS4 reply has wrong version, version should be 4.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Result */
+ switch(socksreq[1]) {
+ case 90:
+ infof(data, "SOCKS4%s request granted.\n", protocol4a?"a":"");
+ break;
+ case 91:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected or failed.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ case 92:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected because SOCKS server cannot connect to "
+ "identd on the client.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ case 93:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", request rejected because the client program and identd "
+ "report different user-ids.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ default:
+ failf(data,
+ "Can't complete SOCKS4 connection to %d.%d.%d.%d:%d. (%d)"
+ ", Unknown.",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ curlx_nonblock(sock, TRUE);
+
+ return CURLE_OK; /* Proxy was successful! */
+}
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the final
+ * destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn)
+{
+ /*
+ According to the RFC1928, section "6. Replies". This is what a SOCK5
+ replies:
+
+ +----+-----+-------+------+----------+----------+
+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+ +----+-----+-------+------+----------+----------+
+ | 1 | 1 | X'00' | 1 | Variable | 2 |
+ +----+-----+-------+------+----------+----------+
+
+ Where:
+
+ o VER protocol version: X'05'
+ o REP Reply field:
+ o X'00' succeeded
+ */
+
+ unsigned char socksreq[600]; /* room for large user/pw (255 max each) */
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ CURLcode code;
+ curl_socket_t sock = conn->sock[sockindex];
+ struct SessionHandle *data = conn->data;
+ long timeout;
+ bool socks5_resolve_local = (conn->proxytype == CURLPROXY_SOCKS5)?TRUE:FALSE;
+ const size_t hostname_len = strlen(hostname);
+ ssize_t len = 0;
+
+ /* RFC1928 chapter 5 specifies max 255 chars for domain name in packet */
+ if(!socks5_resolve_local && hostname_len > 255) {
+ infof(conn->data,"SOCKS5: server resolving disabled for hostnames of "
+ "length > 255 [actual len=%zu]\n", hostname_len);
+ socks5_resolve_local = TRUE;
+ }
+
+ /* get timeout */
+ timeout = Curl_timeleft(data, NULL, TRUE);
+
+ if(timeout < 0) {
+ /* time-out, bail out, go home */
+ failf(data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ curlx_nonblock(sock, TRUE);
+
+ /* wait until socket gets connected */
+ result = Curl_socket_ready(CURL_SOCKET_BAD, sock, timeout);
+
+ if(-1 == result) {
+ failf(conn->data, "SOCKS5: no connection here");
+ return CURLE_COULDNT_CONNECT;
+ }
+ else if(0 == result) {
+ failf(conn->data, "SOCKS5: connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(result & CURL_CSELECT_ERR) {
+ failf(conn->data, "SOCKS5: error occurred during connection");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ socksreq[0] = 5; /* version */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ socksreq[1] = (char)(proxy_name ? 3 : 2); /* number of methods (below) */
+ socksreq[2] = 0; /* no authentication */
+ socksreq[3] = 1; /* gssapi */
+ socksreq[4] = 2; /* username/password */
+#else
+ socksreq[1] = (char)(proxy_name ? 2 : 1); /* number of methods (below) */
+ socksreq[2] = 0; /* no authentication */
+ socksreq[3] = 2; /* username/password */
+#endif
+
+ curlx_nonblock(sock, FALSE);
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, (2 + (int)socksreq[1]),
+ &written);
+ if((code != CURLE_OK) || (written != (2 + (int)socksreq[1]))) {
+ failf(data, "Unable to send initial SOCKS5 request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ curlx_nonblock(sock, TRUE);
+
+ result = Curl_socket_ready(sock, CURL_SOCKET_BAD, timeout);
+
+ if(-1 == result) {
+ failf(conn->data, "SOCKS5 nothing to read");
+ return CURLE_COULDNT_CONNECT;
+ }
+ else if(0 == result) {
+ failf(conn->data, "SOCKS5 read timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(result & CURL_CSELECT_ERR) {
+ failf(conn->data, "SOCKS5 read error occurred");
+ return CURLE_RECV_ERROR;
+ }
+
+ curlx_nonblock(sock, FALSE);
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ if((result != CURLE_OK) || (actualread != 2)) {
+ failf(data, "Unable to receive initial SOCKS5 response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[0] != 5) {
+ failf(data, "Received invalid version in initial SOCKS5 response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(socksreq[1] == 0) {
+ /* Nothing to do, no authentication needed */
+ ;
+ }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ else if(socksreq[1] == 1) {
+ code = Curl_SOCKS5_gssapi_negotiate(sockindex, conn);
+ if(code != CURLE_OK) {
+ failf(data, "Unable to negotiate SOCKS5 gssapi context.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+#endif
+ else if(socksreq[1] == 2) {
+ /* Needs user name and password */
+ size_t proxy_name_len, proxy_password_len;
+ if(proxy_name && proxy_password) {
+ proxy_name_len = strlen(proxy_name);
+ proxy_password_len = strlen(proxy_password);
+ }
+ else {
+ proxy_name_len = 0;
+ proxy_password_len = 0;
+ }
+
+ /* username/password request looks like
+ * +----+------+----------+------+----------+
+ * |VER | ULEN | UNAME | PLEN | PASSWD |
+ * +----+------+----------+------+----------+
+ * | 1 | 1 | 1 to 255 | 1 | 1 to 255 |
+ * +----+------+----------+------+----------+
+ */
+ len = 0;
+ socksreq[len++] = 1; /* username/pw subnegotiation version */
+ socksreq[len++] = (unsigned char) proxy_name_len;
+ if(proxy_name && proxy_name_len)
+ memcpy(socksreq + len, proxy_name, proxy_name_len);
+ len += proxy_name_len;
+ socksreq[len++] = (unsigned char) proxy_password_len;
+ if(proxy_password && proxy_password_len)
+ memcpy(socksreq + len, proxy_password, proxy_password_len);
+ len += proxy_password_len;
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
+ if((code != CURLE_OK) || (len != written)) {
+ failf(data, "Failed to send SOCKS5 sub-negotiation request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 2, &actualread);
+ if((result != CURLE_OK) || (actualread != 2)) {
+ failf(data, "Unable to receive SOCKS5 sub-negotiation response.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] != 0) { /* status */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Everything is good so far, user was authenticated! */
+ }
+ else {
+ /* error */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(socksreq[1] == 255) {
+#else
+ if(socksreq[1] == 1) {
+ failf(data,
+ "SOCKS5 GSSAPI per-message authentication is not supported.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ else if(socksreq[1] == 255) {
+#endif
+ if(!proxy_name || !*proxy_name) {
+ failf(data,
+ "No authentication method was acceptable. (It is quite likely"
+ " that the SOCKS5 server wanted a username/password, since none"
+ " was supplied to the server on this connection.)");
+ }
+ else {
+ failf(data, "No authentication method was acceptable.");
+ }
+ return CURLE_COULDNT_CONNECT;
+ }
+ else {
+ failf(data,
+ "Undocumented SOCKS5 mode attempted to be used by server.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+
+ /* Authentication is complete, now specify destination to the proxy */
+ len = 0;
+ socksreq[len++] = 5; /* version (SOCKS5) */
+ socksreq[len++] = 1; /* connect */
+ socksreq[len++] = 0; /* must be zero */
+
+ if(!socks5_resolve_local) {
+ socksreq[len++] = 3; /* ATYP: domain name = 3 */
+ socksreq[len++] = (char) hostname_len; /* address length */
+ memcpy(&socksreq[len], hostname, hostname_len); /* address str w/o NULL */
+ len += hostname_len;
+ }
+ else {
+ struct Curl_dns_entry *dns;
+ Curl_addrinfo *hp = NULL;
+ int rc = Curl_resolv(conn, hostname, remote_port, &dns);
+
+ if(rc == CURLRESOLV_ERROR)
+ return CURLE_COULDNT_RESOLVE_HOST;
+
+ if(rc == CURLRESOLV_PENDING) {
+ /* this requires that we're in "wait for resolve" state */
+ code = Curl_resolver_wait_resolv(conn, &dns);
+ if(code != CURLE_OK)
+ return code;
+ }
+
+ /*
+ * We cannot use 'hostent' as a struct that Curl_resolv() returns. It
+ * returns a Curl_addrinfo pointer that may not always look the same.
+ */
+ if(dns)
+ hp=dns->addr;
+ if(hp) {
+ struct sockaddr_in *saddr_in;
+#ifdef ENABLE_IPV6
+ struct sockaddr_in6 *saddr_in6;
+#endif
+ int i;
+
+ if(hp->ai_family == AF_INET) {
+ socksreq[len++] = 1; /* ATYP: IPv4 = 1 */
+
+ saddr_in = (struct sockaddr_in*)hp->ai_addr;
+ for(i = 0; i < 4; i++) {
+ socksreq[len++] = ((unsigned char*)&saddr_in->sin_addr.s_addr)[i];
+ infof(data, "%d\n", socksreq[len-1]);
+ }
+ }
+#ifdef ENABLE_IPV6
+ else if(hp->ai_family == AF_INET6) {
+ socksreq[len++] = 4; /* ATYP: IPv6 = 4 */
+
+ saddr_in6 = (struct sockaddr_in6*)hp->ai_addr;
+ for(i = 0; i < 16; i++) {
+ socksreq[len++] = ((unsigned char*)&saddr_in6->sin6_addr.s6_addr)[i];
+ }
+ }
+#endif
+ else
+ hp = NULL; /* fail! */
+
+ Curl_resolv_unlock(data, dns); /* not used anymore from now on */
+ }
+ if(!hp) {
+ failf(data, "Failed to resolve \"%s\" for SOCKS5 connect.",
+ hostname);
+ return CURLE_COULDNT_RESOLVE_HOST;
+ }
+ }
+
+ socksreq[len++] = (unsigned char)((remote_port >> 8) & 0xff); /* PORT MSB */
+ socksreq[len++] = (unsigned char)(remote_port & 0xff); /* PORT LSB */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(conn->socks5_gssapi_enctype) {
+ failf(data, "SOCKS5 gssapi protection not yet implemented.");
+ }
+ else
+#endif
+ code = Curl_write_plain(conn, sock, (char *)socksreq, len, &written);
+
+ if((code != CURLE_OK) || (len != written)) {
+ failf(data, "Failed to send SOCKS5 connect request.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ len = 10; /* minimum packet size is 10 */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(conn->socks5_gssapi_enctype) {
+ failf(data, "SOCKS5 gssapi protection not yet implemented.");
+ }
+ else
+#endif
+ result = Curl_blockread_all(conn, sock, (char *)socksreq,
+ len, &actualread);
+
+ if((result != CURLE_OK) || (len != actualread)) {
+ failf(data, "Failed to receive SOCKS5 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[0] != 5) { /* version */
+ failf(data,
+ "SOCKS5 reply has wrong version, version should be 5.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ if(socksreq[1] != 0) { /* Anything besides 0 is an error */
+ if(socksreq[3] == 1) {
+ failf(data,
+ "Can't complete SOCKS5 connection to %d.%d.%d.%d:%d. (%d)",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ }
+ else if(socksreq[3] == 3) {
+ failf(data,
+ "Can't complete SOCKS5 connection to %s:%d. (%d)",
+ hostname,
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ }
+ else if(socksreq[3] == 4) {
+ failf(data,
+ "Can't complete SOCKS5 connection to %02x%02x:%02x%02x:"
+ "%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%02x%02x:%d. (%d)",
+ (unsigned char)socksreq[4], (unsigned char)socksreq[5],
+ (unsigned char)socksreq[6], (unsigned char)socksreq[7],
+ (unsigned char)socksreq[8], (unsigned char)socksreq[9],
+ (unsigned char)socksreq[10], (unsigned char)socksreq[11],
+ (unsigned char)socksreq[12], (unsigned char)socksreq[13],
+ (unsigned char)socksreq[14], (unsigned char)socksreq[15],
+ (unsigned char)socksreq[16], (unsigned char)socksreq[17],
+ (unsigned char)socksreq[18], (unsigned char)socksreq[19],
+ ((socksreq[8] << 8) | socksreq[9]),
+ socksreq[1]);
+ }
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* Fix: in general, returned BND.ADDR is variable length parameter by RFC
+ 1928, so the reply packet should be read until the end to avoid errors at
+ subsequent protocol level.
+
+ +----+-----+-------+------+----------+----------+
+ |VER | REP | RSV | ATYP | BND.ADDR | BND.PORT |
+ +----+-----+-------+------+----------+----------+
+ | 1 | 1 | X'00' | 1 | Variable | 2 |
+ +----+-----+-------+------+----------+----------+
+
+ ATYP:
+ o IP v4 address: X'01', BND.ADDR = 4 byte
+ o domain name: X'03', BND.ADDR = [ 1 byte length, string ]
+ o IP v6 address: X'04', BND.ADDR = 16 byte
+ */
+
+ /* Calculate real packet size */
+ if(socksreq[3] == 3) {
+ /* domain name */
+ int addrlen = (int) socksreq[4];
+ len = 5 + addrlen + 2;
+ }
+ else if(socksreq[3] == 4) {
+ /* IPv6 */
+ len = 4 + 16 + 2;
+ }
+
+ /* At this point we already read first 10 bytes */
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ if(!conn->socks5_gssapi_enctype) {
+ /* decrypt_gssapi_blockread already read the whole packet */
+#endif
+ if(len > 10) {
+ len -= 10;
+ result = Curl_blockread_all(conn, sock, (char *)&socksreq[10],
+ len, &actualread);
+ if((result != CURLE_OK) || (len != actualread)) {
+ failf(data, "Failed to receive SOCKS5 connect request ack.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ }
+#endif
+
+ curlx_nonblock(sock, TRUE);
+ return CURLE_OK; /* Proxy was successful! */
+}
+
+#endif /* CURL_DISABLE_PROXY */
+
diff --git a/libs/libcurl/src/socks.h b/libs/libcurl/src/socks.h
new file mode 100644
index 0000000000..dc4670b249
--- /dev/null
+++ b/libs/libcurl/src/socks.h
@@ -0,0 +1,77 @@
+#ifndef HEADER_CURL_SOCKS_H
+#define HEADER_CURL_SOCKS_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 CURL_DISABLE_PROXY
+#define Curl_SOCKS4(a,b,c,d,e,f) CURLE_NOT_BUILT_IN
+#define Curl_SOCKS5(a,b,c,d,e,f) CURLE_NOT_BUILT_IN
+#else
+/*
+ * Helper read-from-socket functions. Does the same as Curl_read() but it
+ * blocks until all bytes amount of buffersize will be read. No more, no less.
+ *
+ * This is STUPID BLOCKING behaviour which we frown upon, but right now this
+ * is what we have...
+ */
+int Curl_blockread_all(struct connectdata *conn,
+ curl_socket_t sockfd,
+ char *buf,
+ ssize_t buffersize,
+ ssize_t *n);
+
+/*
+ * This function logs in to a SOCKS4(a) proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS4(const char *proxy_name,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn,
+ bool protocol4a);
+
+/*
+ * This function logs in to a SOCKS5 proxy and sends the specifics to the
+ * final destination server.
+ */
+CURLcode Curl_SOCKS5(const char *proxy_name,
+ const char *proxy_password,
+ const char *hostname,
+ int remote_port,
+ int sockindex,
+ struct connectdata *conn);
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+/*
+ * This function handles the sockss5 gssapie negotiation and initialisation
+ */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn);
+#endif
+
+#endif /* CURL_DISABLE_PROXY */
+
+#endif /* HEADER_CURL_SOCKS_H */
+
diff --git a/libs/libcurl/src/socks_gssapi.c b/libs/libcurl/src/socks_gssapi.c
new file mode 100644
index 0000000000..1f840bd4e0
--- /dev/null
+++ b/libs/libcurl/src/socks_gssapi.c
@@ -0,0 +1,533 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
+ * Copyright (C) 2012, 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"
+
+#ifndef CURL_DISABLE_PROXY
+
+#ifdef HAVE_GSSAPI
+#ifdef HAVE_OLD_GSSMIT
+#define GSS_C_NT_HOSTBASED_SERVICE gss_nt_service_name
+#define NCOMPAT 1
+#endif
+#ifndef gss_nt_service_name
+#define gss_nt_service_name GSS_C_NT_HOSTBASED_SERVICE
+#endif
+
+#include "curl_gssapi.h"
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "timeval.h"
+#include "socks.h"
+#include "warnless.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"
+
+static gss_ctx_id_t gss_context = GSS_C_NO_CONTEXT;
+
+/*
+ * Helper gssapi error functions.
+ */
+static int check_gss_err(struct SessionHandle *data,
+ OM_uint32 major_status,
+ OM_uint32 minor_status,
+ const char* function)
+{
+ if(GSS_ERROR(major_status)) {
+ OM_uint32 maj_stat,min_stat;
+ OM_uint32 msg_ctx = 0;
+ gss_buffer_desc status_string;
+ char buf[1024];
+ size_t len;
+
+ len = 0;
+ msg_ctx = 0;
+ while(!msg_ctx) {
+ /* convert major status code (GSS-API error) to text */
+ maj_stat = gss_display_status(&min_stat, major_status,
+ GSS_C_GSS_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if(maj_stat == GSS_S_COMPLETE) {
+ if(sizeof(buf) > len + status_string.length + 1) {
+ strcpy(buf+len, (char*) status_string.value);
+ len += status_string.length;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ if(sizeof(buf) > len + 3) {
+ strcpy(buf+len, ".\n");
+ len += 2;
+ }
+ msg_ctx = 0;
+ while(!msg_ctx) {
+ /* convert minor status code (underlying routine error) to text */
+ maj_stat = gss_display_status(&min_stat, minor_status,
+ GSS_C_MECH_CODE,
+ GSS_C_NULL_OID,
+ &msg_ctx, &status_string);
+ if(maj_stat == GSS_S_COMPLETE) {
+ if(sizeof(buf) > len + status_string.length)
+ strcpy(buf+len, (char*) status_string.value);
+ gss_release_buffer(&min_stat, &status_string);
+ break;
+ }
+ gss_release_buffer(&min_stat, &status_string);
+ }
+ failf(data, "GSSAPI error: %s failed:\n%s", function, buf);
+ return(1);
+ }
+
+ return(0);
+}
+
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sock = conn->sock[sockindex];
+ CURLcode code;
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ OM_uint32 gss_major_status, gss_minor_status, gss_status;
+ OM_uint32 gss_ret_flags;
+ int gss_conf_state, gss_enc;
+ gss_buffer_desc service = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_send_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_recv_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc gss_w_token = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc* gss_token = GSS_C_NO_BUFFER;
+ gss_name_t server = GSS_C_NO_NAME;
+ gss_name_t gss_client_name = GSS_C_NO_NAME;
+ unsigned short us_length;
+ char *user=NULL;
+ unsigned char socksreq[4]; /* room for gssapi exchange header only */
+ char *serviceptr = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+
+ /* GSSAPI request looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ /* prepare service name */
+ if(strchr(serviceptr,'/')) {
+ service.value = malloc(strlen(serviceptr));
+ if(!service.value)
+ return CURLE_OUT_OF_MEMORY;
+ service.length = strlen(serviceptr);
+ memcpy(service.value, serviceptr, service.length);
+
+ gss_major_status = gss_import_name(&gss_minor_status, &service,
+ (gss_OID) GSS_C_NULL_OID, &server);
+ }
+ else {
+ service.value = malloc(strlen(serviceptr) +strlen(conn->proxy.name)+2);
+ if(!service.value)
+ return CURLE_OUT_OF_MEMORY;
+ service.length = strlen(serviceptr) +strlen(conn->proxy.name)+1;
+ snprintf(service.value, service.length+1, "%s@%s",
+ serviceptr, conn->proxy.name);
+
+ gss_major_status = gss_import_name(&gss_minor_status, &service,
+ gss_nt_service_name, &server);
+ }
+
+ gss_release_buffer(&gss_status, &service); /* clear allocated memory */
+
+ if(check_gss_err(data,gss_major_status,
+ gss_minor_status,"gss_import_name()")) {
+ failf(data, "Failed to create service name.");
+ gss_release_name(&gss_status, &server);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* As long as we need to keep sending some context info, and there's no */
+ /* errors, keep sending it... */
+ for(;;) {
+ gss_major_status = Curl_gss_init_sec_context(data,
+ &gss_minor_status,
+ &gss_context,
+ server,
+ NULL,
+ gss_token,
+ &gss_send_token,
+ &gss_ret_flags);
+
+ if(gss_token != GSS_C_NO_BUFFER)
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ if(check_gss_err(data,gss_major_status,
+ gss_minor_status,"gss_init_sec_context")) {
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to initial GSSAPI token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(gss_send_token.length != 0) {
+ socksreq[0] = 1; /* gssapi subnegotiation version */
+ socksreq[1] = 1; /* authentication message type */
+ us_length = htons((short)gss_send_token.length);
+ memcpy(socksreq+2,&us_length,sizeof(short));
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if((code != CURLE_OK) || (4 != written)) {
+ failf(data, "Failed to send GSSAPI authentication request.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)gss_send_token.value,
+ gss_send_token.length, &written);
+
+ if((code != CURLE_OK) || ((ssize_t)gss_send_token.length != written)) {
+ failf(data, "Failed to send GSSAPI authentication token.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ }
+
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ if(gss_major_status != GSS_S_CONTINUE_NEEDED) break;
+
+ /* analyse response */
+
+ /* GSSAPI response looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result != CURLE_OK || actualread != 4) {
+ failf(data, "Failed to receive GSSAPI authentication response.");
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 1) { /* status / messgae type */
+ failf(data, "Invalid GSSAPI authentication response type (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ gss_recv_token.length=us_length;
+ gss_recv_token.value=malloc(us_length);
+ if(!gss_recv_token.value) {
+ failf(data,
+ "Could not allocate memory for GSSAPI authentication "
+ "response token.");
+ gss_release_name(&gss_status, &server);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
+
+ if(result != CURLE_OK || actualread != us_length) {
+ failf(data, "Failed to receive GSSAPI authentication token.");
+ gss_release_name(&gss_status, &server);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ gss_token = &gss_recv_token;
+ }
+
+ gss_release_name(&gss_status, &server);
+
+ /* Everything is good so far, user was authenticated! */
+ gss_major_status = gss_inquire_context (&gss_minor_status, gss_context,
+ &gss_client_name, NULL, NULL, NULL,
+ NULL, NULL, NULL);
+ if(check_gss_err(data,gss_major_status,
+ gss_minor_status,"gss_inquire_context")) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_major_status = gss_display_name(&gss_minor_status, gss_client_name,
+ &gss_send_token, NULL);
+ if(check_gss_err(data,gss_major_status,
+ gss_minor_status,"gss_display_name")) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ user=malloc(gss_send_token.length+1);
+ if(!user) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(user, gss_send_token.value, gss_send_token.length);
+ user[gss_send_token.length] = '\0';
+ gss_release_name(&gss_status, &gss_client_name);
+ gss_release_buffer(&gss_status, &gss_send_token);
+ infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",user);
+ free(user);
+ user=NULL;
+
+ /* Do encryption */
+ socksreq[0] = 1; /* gssapi subnegotiation version */
+ socksreq[1] = 2; /* encryption message type */
+
+ gss_enc = 0; /* no data protection */
+ /* do confidentiality protection if supported */
+ if(gss_ret_flags & GSS_C_CONF_FLAG)
+ gss_enc = 2;
+ /* else do integrity protection */
+ else if(gss_ret_flags & GSS_C_INTEG_FLAG)
+ gss_enc = 1;
+
+ infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
+ (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality"));
+ /* force for the moment to no data protection */
+ gss_enc = 0;
+ /*
+ * Sending the encryption type in clear seems wrong. It should be
+ * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+ * The NEC reference implementations on which this is based is
+ * therefore at fault
+ *
+ * +------+------+------+.......................+
+ * + ver | mtyp | len | token |
+ * +------+------+------+.......................+
+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+ * +------+------+------+.......................+
+ *
+ * Where:
+ *
+ * - "ver" is the protocol version number, here 1 to represent the
+ * first version of the SOCKS/GSS-API protocol
+ *
+ * - "mtyp" is the message type, here 2 to represent a protection
+ * -level negotiation message
+ *
+ * - "len" is the length of the "token" field in octets
+ *
+ * - "token" is the GSS-API encapsulated protection level
+ *
+ * The token is produced by encapsulating an octet containing the
+ * required protection level using gss_seal()/gss_wrap() with conf_req
+ * set to FALSE. The token is verified using gss_unseal()/
+ * gss_unwrap().
+ *
+ */
+ if(data->set.socks5_gssapi_nec) {
+ us_length = htons((short)1);
+ memcpy(socksreq+2,&us_length,sizeof(short));
+ }
+ else {
+ gss_send_token.length = 1;
+ gss_send_token.value = malloc(1);
+ if(!gss_send_token.value) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(gss_send_token.value, &gss_enc, 1);
+
+ gss_major_status = gss_wrap(&gss_minor_status, gss_context, 0,
+ GSS_C_QOP_DEFAULT, &gss_send_token,
+ &gss_conf_state, &gss_w_token);
+
+ if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_wrap")) {
+ gss_release_buffer(&gss_status, &gss_send_token);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to wrap GSSAPI encryption value into token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_send_token);
+
+ us_length = htons((short)gss_w_token.length);
+ memcpy(socksreq+2,&us_length,sizeof(short));
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if((code != CURLE_OK) || (4 != written)) {
+ failf(data, "Failed to send GSSAPI encryption request.");
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(data->set.socks5_gssapi_nec) {
+ memcpy(socksreq, &gss_enc, 1);
+ code = Curl_write_plain(conn, sock, socksreq, 1, &written);
+ if((code != CURLE_OK) || ( 1 != written)) {
+ failf(data, "Failed to send GSSAPI encryption type.");
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+ else {
+ code = Curl_write_plain(conn, sock, (char *)gss_w_token.value,
+ gss_w_token.length, &written);
+ if((code != CURLE_OK) || ((ssize_t)gss_w_token.length != written)) {
+ failf(data, "Failed to send GSSAPI encryption type.");
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_w_token);
+ }
+
+ result=Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result != CURLE_OK || actualread != 4) {
+ failf(data, "Failed to receive GSSAPI encryption response.");
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 2) { /* status / messgae type */
+ failf(data, "Invalid GSSAPI encryption response type (%d %d).",
+ socksreq[0], socksreq[1]);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ gss_recv_token.length= us_length;
+ gss_recv_token.value=malloc(gss_recv_token.length);
+ if(!gss_recv_token.value) {
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ result=Curl_blockread_all(conn, sock, (char *)gss_recv_token.value,
+ gss_recv_token.length, &actualread);
+
+ if(result != CURLE_OK || actualread != us_length) {
+ failf(data, "Failed to receive GSSAPI encryptrion type.");
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(!data->set.socks5_gssapi_nec) {
+ gss_major_status = gss_unwrap(&gss_minor_status, gss_context,
+ &gss_recv_token, &gss_w_token,
+ 0, GSS_C_QOP_DEFAULT);
+
+ if(check_gss_err(data,gss_major_status,gss_minor_status,"gss_unwrap")) {
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ failf(data, "Failed to unwrap GSSAPI encryption value into token.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ gss_release_buffer(&gss_status, &gss_recv_token);
+
+ if(gss_w_token.length != 1) {
+ failf(data, "Invalid GSSAPI encryption response length (%d).",
+ gss_w_token.length);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq,gss_w_token.value,gss_w_token.length);
+ gss_release_buffer(&gss_status, &gss_w_token);
+ }
+ else {
+ if(gss_recv_token.length != 1) {
+ failf(data, "Invalid GSSAPI encryption response length (%d).",
+ gss_recv_token.length);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq,gss_recv_token.value,gss_recv_token.length);
+ gss_release_buffer(&gss_status, &gss_recv_token);
+ }
+
+ infof(data, "SOCKS5 access with%s protection granted.\n",
+ (socksreq[0]==0)?"out gssapi data":
+ ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
+
+ conn->socks5_gssapi_enctype = socksreq[0];
+ if(socksreq[0] == 0)
+ gss_delete_sec_context(&gss_status, &gss_context, NULL);
+
+ return CURLE_OK;
+}
+#endif
+
+#endif /* CURL_DISABLE_PROXY */
diff --git a/libs/libcurl/src/socks_sspi.c b/libs/libcurl/src/socks_sspi.c
new file mode 100644
index 0000000000..0313de3334
--- /dev/null
+++ b/libs/libcurl/src/socks_sspi.c
@@ -0,0 +1,591 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2009, 2011, Markus Moeller, <markus_moeller@compuserve.com>
+ * Copyright (C) 2012 - 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"
+
+#if defined(USE_WINDOWS_SSPI) && !defined(CURL_DISABLE_PROXY)
+
+#include "urldata.h"
+#include "sendf.h"
+#include "connect.h"
+#include "strerror.h"
+#include "timeval.h"
+#include "socks.h"
+#include "curl_sspi.h"
+#include "curl_multibyte.h"
+#include "warnless.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/*
+ * Definitions required from ntsecapi.h are directly provided below this point
+ * to avoid including ntsecapi.h due to a conflict with OpenSSL's safestack.h
+ */
+#define KERB_WRAP_NO_ENCRYPT 0x80000001
+
+/*
+ * Helper sspi error functions.
+ */
+static int check_sspi_err(struct connectdata *conn,
+ SECURITY_STATUS status,
+ const char* function)
+{
+ if(status != SEC_E_OK &&
+ status != SEC_I_COMPLETE_AND_CONTINUE &&
+ status != SEC_I_COMPLETE_NEEDED &&
+ status != SEC_I_CONTINUE_NEEDED) {
+ failf(conn->data, "SSPI error: %s failed: %s", function,
+ Curl_sspi_strerror(conn, status));
+ return 1;
+ }
+ return 0;
+}
+
+/* This is the SSPI-using version of this function */
+CURLcode Curl_SOCKS5_gssapi_negotiate(int sockindex,
+ struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sock = conn->sock[sockindex];
+ CURLcode code;
+ ssize_t actualread;
+ ssize_t written;
+ int result;
+ /* Needs GSSAPI authentication */
+ SECURITY_STATUS status;
+ unsigned long sspi_ret_flags = 0;
+ int gss_enc;
+ SecBuffer sspi_send_token, sspi_recv_token, sspi_w_token[3];
+ SecBufferDesc input_desc, output_desc, wrap_desc;
+ SecPkgContext_Sizes sspi_sizes;
+ CredHandle cred_handle;
+ CtxtHandle sspi_context;
+ PCtxtHandle context_handle = NULL;
+ SecPkgCredentials_Names names;
+ TimeStamp expiry;
+ char *service_name = NULL;
+ unsigned short us_length;
+ unsigned long qop;
+ unsigned char socksreq[4]; /* room for gssapi exchange header only */
+ char *service = data->set.str[STRING_SOCKS5_GSSAPI_SERVICE];
+
+ /* GSSAPI request looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ /* prepare service name */
+ if(strchr(service, '/')) {
+ service_name = malloc(strlen(service));
+ if(!service_name)
+ return CURLE_OUT_OF_MEMORY;
+ memcpy(service_name, service, strlen(service));
+ }
+ else {
+ service_name = malloc(strlen(service) + strlen(conn->proxy.name) + 2);
+ if(!service_name)
+ return CURLE_OUT_OF_MEMORY;
+ snprintf(service_name,strlen(service) +strlen(conn->proxy.name)+2,"%s/%s",
+ service,conn->proxy.name);
+ }
+
+ input_desc.cBuffers = 1;
+ input_desc.pBuffers = &sspi_recv_token;
+ input_desc.ulVersion = SECBUFFER_VERSION;
+
+ sspi_recv_token.BufferType = SECBUFFER_TOKEN;
+ sspi_recv_token.cbBuffer = 0;
+ sspi_recv_token.pvBuffer = NULL;
+
+ output_desc.cBuffers = 1;
+ output_desc.pBuffers = &sspi_send_token;
+ output_desc.ulVersion = SECBUFFER_VERSION;
+
+ sspi_send_token.BufferType = SECBUFFER_TOKEN;
+ sspi_send_token.cbBuffer = 0;
+ sspi_send_token.pvBuffer = NULL;
+
+ wrap_desc.cBuffers = 3;
+ wrap_desc.pBuffers = sspi_w_token;
+ wrap_desc.ulVersion = SECBUFFER_VERSION;
+
+ cred_handle.dwLower = 0;
+ cred_handle.dwUpper = 0;
+
+ status = s_pSecFn->AcquireCredentialsHandle(NULL,
+ (TCHAR *) TEXT("Kerberos"),
+ SECPKG_CRED_OUTBOUND,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ &cred_handle,
+ &expiry);
+
+ if(check_sspi_err(conn, status, "AcquireCredentialsHandle")) {
+ failf(data, "Failed to acquire credentials.");
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* As long as we need to keep sending some context info, and there's no */
+ /* errors, keep sending it... */
+ for(;;) {
+ TCHAR *sname;
+
+ sname = Curl_convert_UTF8_to_tchar(service_name);
+ if(!sname)
+ return CURLE_OUT_OF_MEMORY;
+
+ status = s_pSecFn->InitializeSecurityContext(&cred_handle,
+ context_handle,
+ sname,
+ ISC_REQ_MUTUAL_AUTH |
+ ISC_REQ_ALLOCATE_MEMORY |
+ ISC_REQ_CONFIDENTIALITY |
+ ISC_REQ_REPLAY_DETECT,
+ 0,
+ SECURITY_NATIVE_DREP,
+ &input_desc,
+ 0,
+ &sspi_context,
+ &output_desc,
+ &sspi_ret_flags,
+ &expiry);
+
+ Curl_unicodefree(sname);
+
+ if(sspi_recv_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ sspi_recv_token.pvBuffer = NULL;
+ sspi_recv_token.cbBuffer = 0;
+ }
+
+ if(check_sspi_err(conn, status, "InitializeSecurityContext")) {
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ failf(data, "Failed to initialise security context.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(sspi_send_token.cbBuffer != 0) {
+ socksreq[0] = 1; /* gssapi subnegotiation version */
+ socksreq[1] = 1; /* authentication message type */
+ us_length = htons((short)sspi_send_token.cbBuffer);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if((code != CURLE_OK) || (4 != written)) {
+ failf(data, "Failed to send SSPI authentication request.");
+ Curl_safefree(service_name);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+ sspi_send_token.cbBuffer, &written);
+ if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
+ failf(data, "Failed to send SSPI authentication token.");
+ Curl_safefree(service_name);
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ }
+
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ sspi_send_token.pvBuffer = NULL;
+ sspi_send_token.cbBuffer = 0;
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ sspi_recv_token.pvBuffer = NULL;
+ sspi_recv_token.cbBuffer = 0;
+ if(status != SEC_I_CONTINUE_NEEDED)
+ break;
+
+ /* analyse response */
+
+ /* GSSAPI response looks like
+ * +----+------+-----+----------------+
+ * |VER | MTYP | LEN | TOKEN |
+ * +----+------+----------------------+
+ * | 1 | 1 | 2 | up to 2^16 - 1 |
+ * +----+------+-----+----------------+
+ */
+
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result != CURLE_OK || actualread != 4) {
+ failf(data, "Failed to receive SSPI authentication response.");
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 1) { /* status / messgae type */
+ failf(data, "Invalid SSPI authentication response type (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ sspi_recv_token.cbBuffer = us_length;
+ sspi_recv_token.pvBuffer = malloc(us_length);
+
+ if(!sspi_recv_token.pvBuffer) {
+ Curl_safefree(service_name);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ result = Curl_blockread_all(conn, sock, (char *)sspi_recv_token.pvBuffer,
+ sspi_recv_token.cbBuffer, &actualread);
+
+ if(result != CURLE_OK || actualread != us_length) {
+ failf(data, "Failed to receive SSPI authentication token.");
+ Curl_safefree(service_name);
+ s_pSecFn->FreeContextBuffer(sspi_recv_token.pvBuffer);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ context_handle = &sspi_context;
+ }
+
+ Curl_safefree(service_name);
+
+ /* Everything is good so far, user was authenticated! */
+ status = s_pSecFn->QueryCredentialsAttributes(&cred_handle,
+ SECPKG_CRED_ATTR_NAMES,
+ &names);
+ s_pSecFn->FreeCredentialsHandle(&cred_handle);
+ if(check_sspi_err(conn, status, "QueryCredentialAttributes")) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
+ failf(data, "Failed to determine user name.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ infof(data, "SOCKS5 server authencticated user %s with gssapi.\n",
+ names.sUserName);
+ s_pSecFn->FreeContextBuffer(names.sUserName);
+
+ /* Do encryption */
+ socksreq[0] = 1; /* gssapi subnegotiation version */
+ socksreq[1] = 2; /* encryption message type */
+
+ gss_enc = 0; /* no data protection */
+ /* do confidentiality protection if supported */
+ if(sspi_ret_flags & ISC_REQ_CONFIDENTIALITY)
+ gss_enc = 2;
+ /* else do integrity protection */
+ else if(sspi_ret_flags & ISC_REQ_INTEGRITY)
+ gss_enc = 1;
+
+ infof(data, "SOCKS5 server supports gssapi %s data protection.\n",
+ (gss_enc==0)?"no":((gss_enc==1)?"integrity":"confidentiality") );
+ /* force to no data protection, avoid encryption/decryption for now */
+ gss_enc = 0;
+ /*
+ * Sending the encryption type in clear seems wrong. It should be
+ * protected with gss_seal()/gss_wrap(). See RFC1961 extract below
+ * The NEC reference implementations on which this is based is
+ * therefore at fault
+ *
+ * +------+------+------+.......................+
+ * + ver | mtyp | len | token |
+ * +------+------+------+.......................+
+ * + 0x01 | 0x02 | 0x02 | up to 2^16 - 1 octets |
+ * +------+------+------+.......................+
+ *
+ * Where:
+ *
+ * - "ver" is the protocol version number, here 1 to represent the
+ * first version of the SOCKS/GSS-API protocol
+ *
+ * - "mtyp" is the message type, here 2 to represent a protection
+ * -level negotiation message
+ *
+ * - "len" is the length of the "token" field in octets
+ *
+ * - "token" is the GSS-API encapsulated protection level
+ *
+ * The token is produced by encapsulating an octet containing the
+ * required protection level using gss_seal()/gss_wrap() with conf_req
+ * set to FALSE. The token is verified using gss_unseal()/
+ * gss_unwrap().
+ *
+ */
+
+ if(data->set.socks5_gssapi_nec) {
+ us_length = htons((short)1);
+ memcpy(socksreq+2, &us_length, sizeof(short));
+ }
+ else {
+ status = s_pSecFn->QueryContextAttributes(&sspi_context,
+ SECPKG_ATTR_SIZES,
+ &sspi_sizes);
+ if(check_sspi_err(conn, status, "QueryContextAttributes")) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ sspi_w_token[0].cbBuffer = sspi_sizes.cbSecurityTrailer;
+ sspi_w_token[0].BufferType = SECBUFFER_TOKEN;
+ sspi_w_token[0].pvBuffer = malloc(sspi_sizes.cbSecurityTrailer);
+
+ if(!sspi_w_token[0].pvBuffer) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ sspi_w_token[1].cbBuffer = 1;
+ sspi_w_token[1].pvBuffer = malloc(1);
+ if(!sspi_w_token[1].pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(sspi_w_token[1].pvBuffer,&gss_enc,1);
+ sspi_w_token[2].BufferType = SECBUFFER_PADDING;
+ sspi_w_token[2].cbBuffer = sspi_sizes.cbBlockSize;
+ sspi_w_token[2].pvBuffer = malloc(sspi_sizes.cbBlockSize);
+ if(!sspi_w_token[2].pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ status = s_pSecFn->EncryptMessage(&sspi_context,
+ KERB_WRAP_NO_ENCRYPT,
+ &wrap_desc,
+ 0);
+ if(check_sspi_err(conn, status, "EncryptMessage")) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+ sspi_send_token.cbBuffer = sspi_w_token[0].cbBuffer
+ + sspi_w_token[1].cbBuffer
+ + sspi_w_token[2].cbBuffer;
+ sspi_send_token.pvBuffer = malloc(sspi_send_token.cbBuffer);
+ if(!sspi_send_token.pvBuffer) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ memcpy(sspi_send_token.pvBuffer, sspi_w_token[0].pvBuffer,
+ sspi_w_token[0].cbBuffer);
+ memcpy((PUCHAR) sspi_send_token.pvBuffer +(int)sspi_w_token[0].cbBuffer,
+ sspi_w_token[1].pvBuffer, sspi_w_token[1].cbBuffer);
+ memcpy((PUCHAR) sspi_send_token.pvBuffer
+ +sspi_w_token[0].cbBuffer
+ +sspi_w_token[1].cbBuffer,
+ sspi_w_token[2].pvBuffer, sspi_w_token[2].cbBuffer);
+
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ sspi_w_token[0].pvBuffer = NULL;
+ sspi_w_token[0].cbBuffer = 0;
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ sspi_w_token[1].pvBuffer = NULL;
+ sspi_w_token[1].cbBuffer = 0;
+ s_pSecFn->FreeContextBuffer(sspi_w_token[2].pvBuffer);
+ sspi_w_token[2].pvBuffer = NULL;
+ sspi_w_token[2].cbBuffer = 0;
+
+ us_length = htons((short)sspi_send_token.cbBuffer);
+ memcpy(socksreq+2,&us_length,sizeof(short));
+ }
+
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 4, &written);
+ if((code != CURLE_OK) || (4 != written)) {
+ failf(data, "Failed to send SSPI encryption request.");
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(data->set.socks5_gssapi_nec) {
+ memcpy(socksreq,&gss_enc,1);
+ code = Curl_write_plain(conn, sock, (char *)socksreq, 1, &written);
+ if((code != CURLE_OK) || (1 != written)) {
+ failf(data, "Failed to send SSPI encryption type.");
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ }
+ else {
+ code = Curl_write_plain(conn, sock, (char *)sspi_send_token.pvBuffer,
+ sspi_send_token.cbBuffer, &written);
+ if((code != CURLE_OK) || (sspi_send_token.cbBuffer != (size_t)written)) {
+ failf(data, "Failed to send SSPI encryption type.");
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ s_pSecFn->FreeContextBuffer(sspi_send_token.pvBuffer);
+ }
+
+ result = Curl_blockread_all(conn, sock, (char *)socksreq, 4, &actualread);
+ if(result != CURLE_OK || actualread != 4) {
+ failf(data, "Failed to receive SSPI encryption response.");
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ /* ignore the first (VER) byte */
+ if(socksreq[1] == 255) { /* status / message type */
+ failf(data, "User was rejected by the SOCKS5 server (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(socksreq[1] != 2) { /* status / message type */
+ failf(data, "Invalid SSPI encryption response type (%u %u).",
+ (unsigned int)socksreq[0], (unsigned int)socksreq[1]);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(&us_length, socksreq+2, sizeof(short));
+ us_length = ntohs(us_length);
+
+ sspi_w_token[0].cbBuffer = us_length;
+ sspi_w_token[0].pvBuffer = malloc(us_length);
+ if(!sspi_w_token[0].pvBuffer) {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ result = Curl_blockread_all(conn, sock, (char *)sspi_w_token[0].pvBuffer,
+ sspi_w_token[0].cbBuffer, &actualread);
+
+ if(result != CURLE_OK || actualread != us_length) {
+ failf(data, "Failed to receive SSPI encryption type.");
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+
+ if(!data->set.socks5_gssapi_nec) {
+ wrap_desc.cBuffers = 2;
+ sspi_w_token[0].BufferType = SECBUFFER_STREAM;
+ sspi_w_token[1].BufferType = SECBUFFER_DATA;
+ sspi_w_token[1].cbBuffer = 0;
+ sspi_w_token[1].pvBuffer = NULL;
+
+ status = s_pSecFn->DecryptMessage(&sspi_context,
+ &wrap_desc,
+ 0,
+ &qop);
+
+ if(check_sspi_err(conn, status, "DecryptMessage")) {
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ failf(data, "Failed to query security context attributes.");
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ if(sspi_w_token[1].cbBuffer != 1) {
+ failf(data, "Invalid SSPI encryption response length (%lu).",
+ (unsigned long)sspi_w_token[1].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+
+ memcpy(socksreq,sspi_w_token[1].pvBuffer,sspi_w_token[1].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[1].pvBuffer);
+ }
+ else {
+ if(sspi_w_token[0].cbBuffer != 1) {
+ failf(data, "Invalid SSPI encryption response length (%lu).",
+ (unsigned long)sspi_w_token[0].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ return CURLE_COULDNT_CONNECT;
+ }
+ memcpy(socksreq,sspi_w_token[0].pvBuffer,sspi_w_token[0].cbBuffer);
+ s_pSecFn->FreeContextBuffer(sspi_w_token[0].pvBuffer);
+ }
+
+ infof(data, "SOCKS5 access with%s protection granted.\n",
+ (socksreq[0]==0)?"out gssapi data":
+ ((socksreq[0]==1)?" gssapi integrity":" gssapi confidentiality"));
+
+ /* For later use if encryption is required
+ conn->socks5_gssapi_enctype = socksreq[0];
+ if(socksreq[0] != 0)
+ conn->socks5_sspi_context = sspi_context;
+ else {
+ s_pSecFn->DeleteSecurityContext(&sspi_context);
+ conn->socks5_sspi_context = sspi_context;
+ }
+ */
+ return CURLE_OK;
+}
+#endif
diff --git a/libs/libcurl/src/speedcheck.c b/libs/libcurl/src/speedcheck.c
new file mode 100644
index 0000000000..ea17a59754
--- /dev/null
+++ b/libs/libcurl/src/speedcheck.c
@@ -0,0 +1,74 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "multiif.h"
+#include "speedcheck.h"
+
+void Curl_speedinit(struct SessionHandle *data)
+{
+ memset(&data->state.keeps_speed, 0, sizeof(struct timeval));
+}
+
+CURLcode Curl_speedcheck(struct SessionHandle *data,
+ struct timeval now)
+{
+ if((data->progress.current_speed >= 0) &&
+ data->set.low_speed_time &&
+ (Curl_tvlong(data->state.keeps_speed) != 0) &&
+ (data->progress.current_speed < data->set.low_speed_limit)) {
+ long howlong = Curl_tvdiff(now, data->state.keeps_speed);
+ long nextcheck = (data->set.low_speed_time * 1000) - howlong;
+
+ /* We are now below the "low speed limit". If we are below it
+ for "low speed time" seconds we consider that enough reason
+ to abort the download. */
+ if(nextcheck <= 0) {
+ /* we have been this slow for long enough, now die */
+ failf(data,
+ "Operation too slow. "
+ "Less than %ld bytes/sec transferred the last %ld seconds",
+ data->set.low_speed_limit,
+ data->set.low_speed_time);
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ else {
+ /* wait complete low_speed_time */
+ Curl_expire(data, nextcheck);
+ }
+ }
+ else {
+ /* we keep up the required speed all right */
+ data->state.keeps_speed = now;
+
+ if(data->set.low_speed_limit)
+ /* if there is a low speed limit enabled, we set the expire timer to
+ make this connection's speed get checked again no later than when
+ this time is up */
+ Curl_expire(data, data->set.low_speed_time*1000);
+ }
+ return CURLE_OK;
+}
diff --git a/libs/libcurl/src/speedcheck.h b/libs/libcurl/src/speedcheck.h
new file mode 100644
index 0000000000..786cd1215a
--- /dev/null
+++ b/libs/libcurl/src/speedcheck.h
@@ -0,0 +1,33 @@
+#ifndef HEADER_CURL_SPEEDCHECK_H
+#define HEADER_CURL_SPEEDCHECK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "timeval.h"
+
+void Curl_speedinit(struct SessionHandle *data);
+CURLcode Curl_speedcheck(struct SessionHandle *data,
+ struct timeval now);
+
+#endif /* HEADER_CURL_SPEEDCHECK_H */
diff --git a/libs/libcurl/src/splay.c b/libs/libcurl/src/splay.c
new file mode 100644
index 0000000000..3570712d43
--- /dev/null
+++ b/libs/libcurl/src/splay.c
@@ -0,0 +1,288 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2011, 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 "splay.h"
+
+/*
+ * This macro compares two node keys i and j and returns:
+ *
+ * negative value: when i is smaller than j
+ * zero : when i is equal to j
+ * positive when : when i is larger than j
+ */
+#define compare(i,j) Curl_splaycomparekeys((i),(j))
+
+/*
+ * Splay using the key i (which may or may not be in the tree.) The starting
+ * root is t.
+ */
+struct Curl_tree *Curl_splay(struct timeval i,
+ struct Curl_tree *t)
+{
+ struct Curl_tree N, *l, *r, *y;
+ long comp;
+
+ if(t == NULL)
+ return t;
+ N.smaller = N.larger = NULL;
+ l = r = &N;
+
+ for(;;) {
+ comp = compare(i, t->key);
+ if(comp < 0) {
+ if(t->smaller == NULL)
+ break;
+ if(compare(i, t->smaller->key) < 0) {
+ y = t->smaller; /* rotate smaller */
+ t->smaller = y->larger;
+ y->larger = t;
+ t = y;
+ if(t->smaller == NULL)
+ break;
+ }
+ r->smaller = t; /* link smaller */
+ r = t;
+ t = t->smaller;
+ }
+ else if(comp > 0) {
+ if(t->larger == NULL)
+ break;
+ if(compare(i, t->larger->key) > 0) {
+ y = t->larger; /* rotate larger */
+ t->larger = y->smaller;
+ y->smaller = t;
+ t = y;
+ if(t->larger == NULL)
+ break;
+ }
+ l->larger = t; /* link larger */
+ l = t;
+ t = t->larger;
+ }
+ else
+ break;
+ }
+
+ l->larger = t->smaller; /* assemble */
+ r->smaller = t->larger;
+ t->smaller = N.larger;
+ t->larger = N.smaller;
+
+ return t;
+}
+
+/* Insert key i into the tree t. Return a pointer to the resulting tree or
+ * NULL if something went wrong.
+ *
+ * @unittest: 1309
+ */
+struct Curl_tree *Curl_splayinsert(struct timeval i,
+ struct Curl_tree *t,
+ struct Curl_tree *node)
+{
+ static struct timeval KEY_NOTUSED = {-1,-1}; /* will *NEVER* appear */
+
+ if(node == NULL)
+ return t;
+
+ if(t != NULL) {
+ t = Curl_splay(i,t);
+ if(compare(i, t->key)==0) {
+ /* There already exists a node in the tree with the very same key. Build
+ a linked list of nodes. We make the new 'node' struct the new master
+ node and make the previous node the first one in the 'same' list. */
+
+ node->same = t;
+ node->key = i;
+ node->smaller = t->smaller;
+ node->larger = t->larger;
+
+ t->smaller = node; /* in the sub node for this same key, we use the
+ smaller pointer to point back to the master
+ node */
+
+ t->key = KEY_NOTUSED; /* and we set the key in the sub node to NOTUSED
+ to quickly identify this node as a subnode */
+
+ return node; /* new root node */
+ }
+ }
+
+ if(t == NULL) {
+ node->smaller = node->larger = NULL;
+ }
+ else if(compare(i, t->key) < 0) {
+ node->smaller = t->smaller;
+ node->larger = t;
+ t->smaller = NULL;
+
+ }
+ else {
+ node->larger = t->larger;
+ node->smaller = t;
+ t->larger = NULL;
+ }
+ node->key = i;
+
+ node->same = NULL; /* no identical node (yet) */
+ return node;
+}
+
+/* Finds and deletes the best-fit node from the tree. Return a pointer to the
+ resulting tree. best-fit means the node with the given or lower key */
+struct Curl_tree *Curl_splaygetbest(struct timeval i,
+ struct Curl_tree *t,
+ struct Curl_tree **removed)
+{
+ struct Curl_tree *x;
+
+ if(!t) {
+ *removed = NULL; /* none removed since there was no root */
+ return NULL;
+ }
+
+ t = Curl_splay(i,t);
+ if(compare(i, t->key) < 0) {
+ /* too big node, try the smaller chain */
+ if(t->smaller)
+ t=Curl_splay(t->smaller->key, t);
+ else {
+ /* fail */
+ *removed = NULL;
+ return t;
+ }
+ }
+
+ if(compare(i, t->key) >= 0) { /* found it */
+ /* FIRST! Check if there is a list with identical keys */
+ x = t->same;
+ if(x) {
+ /* there is, pick one from the list */
+
+ /* 'x' is the new root node */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+
+ *removed = t;
+ return x; /* new root */
+ }
+
+ if(t->smaller == NULL) {
+ x = t->larger;
+ }
+ else {
+ x = Curl_splay(i, t->smaller);
+ x->larger = t->larger;
+ }
+ *removed = t;
+
+ return x;
+ }
+ else {
+ *removed = NULL; /* no match */
+ return t; /* It wasn't there */
+ }
+}
+
+
+/* Deletes the very node we point out from the tree if it's there. Stores a
+ * pointer to the new resulting tree in 'newroot'.
+ *
+ * Returns zero on success and non-zero on errors! TODO: document error codes.
+ * When returning error, it does not touch the 'newroot' pointer.
+ *
+ * NOTE: when the last node of the tree is removed, there's no tree left so
+ * 'newroot' will be made to point to NULL.
+ *
+ * @unittest: 1309
+ */
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+ struct Curl_tree *removenode,
+ struct Curl_tree **newroot)
+{
+ static struct timeval KEY_NOTUSED = {-1,-1}; /* will *NEVER* appear */
+ struct Curl_tree *x;
+
+ if(!t || !removenode)
+ return 1;
+
+ if(compare(KEY_NOTUSED, removenode->key) == 0) {
+ /* Key set to NOTUSED means it is a subnode within a 'same' linked list
+ and thus we can unlink it easily. The 'smaller' link of a subnode
+ links to the parent node. */
+ if(removenode->smaller == NULL)
+ return 3;
+
+ removenode->smaller->same = removenode->same;
+ if(removenode->same)
+ removenode->same->smaller = removenode->smaller;
+
+ /* Ensures that double-remove gets caught. */
+ removenode->smaller = NULL;
+
+ /* voila, we're done! */
+ *newroot = t; /* return the same root */
+ return 0;
+ }
+
+ t = Curl_splay(removenode->key, t);
+
+ /* First make sure that we got the same root node as the one we want
+ to remove, as otherwise we might be trying to remove a node that
+ isn't actually in the tree.
+
+ We cannot just compare the keys here as a double remove in quick
+ succession of a node with key != KEY_NOTUSED && same != NULL
+ could return the same key but a different node. */
+ if(t != removenode)
+ return 2;
+
+ /* Check if there is a list with identical sizes, as then we're trying to
+ remove the root node of a list of nodes with identical keys. */
+ x = t->same;
+ if(x) {
+ /* 'x' is the new root node, we just make it use the root node's
+ smaller/larger links */
+
+ x->key = t->key;
+ x->larger = t->larger;
+ x->smaller = t->smaller;
+ }
+ else {
+ /* Remove the root node */
+ if(t->smaller == NULL)
+ x = t->larger;
+ else {
+ x = Curl_splay(removenode->key, t->smaller);
+ x->larger = t->larger;
+ }
+ }
+
+ *newroot = x; /* store new root pointer */
+
+ return 0;
+}
+
diff --git a/libs/libcurl/src/splay.h b/libs/libcurl/src/splay.h
new file mode 100644
index 0000000000..5f9ef24cc6
--- /dev/null
+++ b/libs/libcurl/src/splay.h
@@ -0,0 +1,66 @@
+#ifndef HEADER_CURL_SPLAY_H
+#define HEADER_CURL_SPLAY_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1997 - 2011, 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"
+
+struct Curl_tree {
+ struct Curl_tree *smaller; /* smaller node */
+ struct Curl_tree *larger; /* larger node */
+ struct Curl_tree *same; /* points to a node with identical key */
+ struct timeval key; /* this node's "sort" key */
+ void *payload; /* data the splay code doesn't care about */
+};
+
+struct Curl_tree *Curl_splay(struct timeval i,
+ struct Curl_tree *t);
+
+struct Curl_tree *Curl_splayinsert(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree *newnode);
+
+#if 0
+struct Curl_tree *Curl_splayremove(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree **removed);
+#endif
+
+struct Curl_tree *Curl_splaygetbest(struct timeval key,
+ struct Curl_tree *t,
+ struct Curl_tree **removed);
+
+int Curl_splayremovebyaddr(struct Curl_tree *t,
+ struct Curl_tree *removenode,
+ struct Curl_tree **newroot);
+
+#define Curl_splaycomparekeys(i,j) ( ((i.tv_sec) < (j.tv_sec)) ? -1 : \
+ ( ((i.tv_sec) > (j.tv_sec)) ? 1 : \
+ ( ((i.tv_usec) < (j.tv_usec)) ? -1 : \
+ ( ((i.tv_usec) > (j.tv_usec)) ? 1 : 0 ))))
+
+#ifdef DEBUGBUILD
+void Curl_splayprint(struct Curl_tree * t, int d, char output);
+#else
+#define Curl_splayprint(x,y,z) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_SPLAY_H */
diff --git a/libs/libcurl/src/ssh.c b/libs/libcurl/src/ssh.c
new file mode 100644
index 0000000000..c213225db4
--- /dev/null
+++ b/libs/libcurl/src/ssh.c
@@ -0,0 +1,3271 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/* #define CURL_LIBSSH2_DEBUG */
+
+#include "curl_setup.h"
+
+#ifdef USE_LIBSSH2
+
+#ifdef HAVE_LIMITS_H
+# include <limits.h>
+#endif
+
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_UTSNAME_H
+#include <sys/utsname.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#if (defined(NETWARE) && defined(__NOVELL_LIBC__))
+#undef in_addr_t
+#define in_addr_t unsigned long
+#endif
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "sendf.h"
+#include "hostip.h"
+#include "progress.h"
+#include "transfer.h"
+#include "escape.h"
+#include "http.h" /* for HTTP proxy tunnel stuff */
+#include "ssh.h"
+#include "url.h"
+#include "speedcheck.h"
+#include "getinfo.h"
+
+#include "strequal.h"
+#include "sslgen.h"
+#include "connect.h"
+#include "strerror.h"
+#include "inet_ntop.h"
+#include "parsedate.h" /* for the week day and month names */
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "strtoofft.h"
+#include "multiif.h"
+#include "select.h"
+#include "warnless.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"
+
+#ifdef WIN32
+# undef PATH_MAX
+# define PATH_MAX MAX_PATH
+#endif
+
+#ifndef PATH_MAX
+#define PATH_MAX 1024 /* just an extra precaution since there are systems that
+ have their definition hidden well */
+#endif
+
+#define sftp_libssh2_last_error(s) curlx_ultosi(libssh2_sftp_last_error(s))
+
+#define sftp_libssh2_realpath(s,p,t,m) \
+ libssh2_sftp_symlink_ex((s), (p), curlx_uztoui(strlen(p)), \
+ (t), (m), LIBSSH2_SFTP_REALPATH)
+
+/* Local functions: */
+static const char *sftp_libssh2_strerror(int err);
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc);
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc);
+static LIBSSH2_FREE_FUNC(my_libssh2_free);
+
+static CURLcode get_pathname(const char **cpp, char **path);
+
+static CURLcode ssh_connect(struct connectdata *conn, bool *done);
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode ssh_do(struct connectdata *conn, bool *done);
+
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+ char *homedir, /* when SFTP is used */
+ char **path);
+
+static CURLcode scp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode scp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection);
+
+static CURLcode sftp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode sftp_doing(struct connectdata *conn,
+ bool *dophase_done);
+static CURLcode sftp_disconnect(struct connectdata *conn, bool dead);
+static
+CURLcode sftp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done);
+
+static int ssh_getsock(struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks);
+
+static int ssh_perform_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks
+ number of sockets */
+ int numsocks);
+
+static CURLcode ssh_setup_connection(struct connectdata *conn);
+
+/*
+ * SCP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_scp = {
+ "SCP", /* scheme */
+ ssh_setup_connection, /* setup_connection */
+ ssh_do, /* do_it */
+ scp_done, /* done */
+ ZERO_NULL, /* do_more */
+ ssh_connect, /* connect_it */
+ ssh_multi_statemach, /* connecting */
+ scp_doing, /* doing */
+ ssh_getsock, /* proto_getsock */
+ ssh_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ssh_perform_getsock, /* perform_getsock */
+ scp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SSH, /* defport */
+ CURLPROTO_SCP, /* protocol */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+/*
+ * SFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_sftp = {
+ "SFTP", /* scheme */
+ ssh_setup_connection, /* setup_connection */
+ ssh_do, /* do_it */
+ sftp_done, /* done */
+ ZERO_NULL, /* do_more */
+ ssh_connect, /* connect_it */
+ ssh_multi_statemach, /* connecting */
+ sftp_doing, /* doing */
+ ssh_getsock, /* proto_getsock */
+ ssh_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ssh_perform_getsock, /* perform_getsock */
+ sftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_SSH, /* defport */
+ CURLPROTO_SFTP, /* protocol */
+ PROTOPT_DIRLOCK | PROTOPT_CLOSEACTION
+ | PROTOPT_NOURLQUERY /* flags */
+};
+
+static void
+kbd_callback(const char *name, int name_len, const char *instruction,
+ int instruction_len, int num_prompts,
+ const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
+ LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses,
+ void **abstract)
+{
+ struct connectdata *conn = (struct connectdata *)*abstract;
+
+#ifdef CURL_LIBSSH2_DEBUG
+ fprintf(stderr, "name=%s\n", name);
+ fprintf(stderr, "name_len=%d\n", name_len);
+ fprintf(stderr, "instruction=%s\n", instruction);
+ fprintf(stderr, "instruction_len=%d\n", instruction_len);
+ fprintf(stderr, "num_prompts=%d\n", num_prompts);
+#else
+ (void)name;
+ (void)name_len;
+ (void)instruction;
+ (void)instruction_len;
+#endif /* CURL_LIBSSH2_DEBUG */
+ if(num_prompts == 1) {
+ responses[0].text = strdup(conn->passwd);
+ responses[0].length = curlx_uztoui(strlen(conn->passwd));
+ }
+ (void)prompts;
+ (void)abstract;
+} /* kbd_callback */
+
+static CURLcode sftp_libssh2_error_to_CURLE(int err)
+{
+ switch (err) {
+ case LIBSSH2_FX_OK:
+ return CURLE_OK;
+
+ case LIBSSH2_FX_NO_SUCH_FILE:
+ case LIBSSH2_FX_NO_SUCH_PATH:
+ return CURLE_REMOTE_FILE_NOT_FOUND;
+
+ case LIBSSH2_FX_PERMISSION_DENIED:
+ case LIBSSH2_FX_WRITE_PROTECT:
+ case LIBSSH2_FX_LOCK_CONFlICT:
+ return CURLE_REMOTE_ACCESS_DENIED;
+
+ case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+ case LIBSSH2_FX_QUOTA_EXCEEDED:
+ return CURLE_REMOTE_DISK_FULL;
+
+ case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+ return CURLE_REMOTE_FILE_EXISTS;
+
+ case LIBSSH2_FX_DIR_NOT_EMPTY:
+ return CURLE_QUOTE_ERROR;
+
+ default:
+ break;
+ }
+
+ return CURLE_SSH;
+}
+
+static CURLcode libssh2_session_error_to_CURLE(int err)
+{
+ switch (err) {
+ /* Ordered by order of appearance in libssh2.h */
+ case LIBSSH2_ERROR_NONE:
+ return CURLE_OK;
+
+ case LIBSSH2_ERROR_SOCKET_NONE:
+ return CURLE_COULDNT_CONNECT;
+
+ case LIBSSH2_ERROR_ALLOC:
+ return CURLE_OUT_OF_MEMORY;
+
+ case LIBSSH2_ERROR_SOCKET_SEND:
+ return CURLE_SEND_ERROR;
+
+ case LIBSSH2_ERROR_HOSTKEY_INIT:
+ case LIBSSH2_ERROR_HOSTKEY_SIGN:
+ case LIBSSH2_ERROR_PUBLICKEY_UNRECOGNIZED:
+ case LIBSSH2_ERROR_PUBLICKEY_UNVERIFIED:
+ return CURLE_PEER_FAILED_VERIFICATION;
+
+ case LIBSSH2_ERROR_PASSWORD_EXPIRED:
+ return CURLE_LOGIN_DENIED;
+
+ case LIBSSH2_ERROR_SOCKET_TIMEOUT:
+ case LIBSSH2_ERROR_TIMEOUT:
+ return CURLE_OPERATION_TIMEDOUT;
+
+ case LIBSSH2_ERROR_EAGAIN:
+ return CURLE_AGAIN;
+ }
+
+ /* TODO: map some more of the libssh2 errors to the more appropriate CURLcode
+ error code, and possibly add a few new SSH-related one. We must however
+ not return or even depend on libssh2 errors in the public libcurl API */
+
+ return CURLE_SSH;
+}
+
+static LIBSSH2_ALLOC_FUNC(my_libssh2_malloc)
+{
+ (void)abstract; /* arg not used */
+ return malloc(count);
+}
+
+static LIBSSH2_REALLOC_FUNC(my_libssh2_realloc)
+{
+ (void)abstract; /* arg not used */
+ return realloc(ptr, count);
+}
+
+static LIBSSH2_FREE_FUNC(my_libssh2_free)
+{
+ (void)abstract; /* arg not used */
+ if(ptr) /* ssh2 agent sometimes call free with null ptr */
+ free(ptr);
+}
+
+/*
+ * SSH State machine related code
+ */
+/* This is the ONLY way to change SSH state! */
+static void state(struct connectdata *conn, sshstate nowstate)
+{
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ /* for debug purposes */
+ static const char * const names[] = {
+ "SSH_STOP",
+ "SSH_INIT",
+ "SSH_S_STARTUP",
+ "SSH_HOSTKEY",
+ "SSH_AUTHLIST",
+ "SSH_AUTH_PKEY_INIT",
+ "SSH_AUTH_PKEY",
+ "SSH_AUTH_PASS_INIT",
+ "SSH_AUTH_PASS",
+ "SSH_AUTH_AGENT_INIT",
+ "SSH_AUTH_AGENT_LIST",
+ "SSH_AUTH_AGENT",
+ "SSH_AUTH_HOST_INIT",
+ "SSH_AUTH_HOST",
+ "SSH_AUTH_KEY_INIT",
+ "SSH_AUTH_KEY",
+ "SSH_AUTH_DONE",
+ "SSH_SFTP_INIT",
+ "SSH_SFTP_REALPATH",
+ "SSH_SFTP_QUOTE_INIT",
+ "SSH_SFTP_POSTQUOTE_INIT",
+ "SSH_SFTP_QUOTE",
+ "SSH_SFTP_NEXT_QUOTE",
+ "SSH_SFTP_QUOTE_STAT",
+ "SSH_SFTP_QUOTE_SETSTAT",
+ "SSH_SFTP_QUOTE_SYMLINK",
+ "SSH_SFTP_QUOTE_MKDIR",
+ "SSH_SFTP_QUOTE_RENAME",
+ "SSH_SFTP_QUOTE_RMDIR",
+ "SSH_SFTP_QUOTE_UNLINK",
+ "SSH_SFTP_TRANS_INIT",
+ "SSH_SFTP_UPLOAD_INIT",
+ "SSH_SFTP_CREATE_DIRS_INIT",
+ "SSH_SFTP_CREATE_DIRS",
+ "SSH_SFTP_CREATE_DIRS_MKDIR",
+ "SSH_SFTP_READDIR_INIT",
+ "SSH_SFTP_READDIR",
+ "SSH_SFTP_READDIR_LINK",
+ "SSH_SFTP_READDIR_BOTTOM",
+ "SSH_SFTP_READDIR_DONE",
+ "SSH_SFTP_DOWNLOAD_INIT",
+ "SSH_SFTP_DOWNLOAD_STAT",
+ "SSH_SFTP_CLOSE",
+ "SSH_SFTP_SHUTDOWN",
+ "SSH_SCP_TRANS_INIT",
+ "SSH_SCP_UPLOAD_INIT",
+ "SSH_SCP_DOWNLOAD_INIT",
+ "SSH_SCP_DONE",
+ "SSH_SCP_SEND_EOF",
+ "SSH_SCP_WAIT_EOF",
+ "SSH_SCP_WAIT_CLOSE",
+ "SSH_SCP_CHANNEL_FREE",
+ "SSH_SESSION_DISCONNECT",
+ "SSH_SESSION_FREE",
+ "QUIT"
+ };
+#endif
+ struct ssh_conn *sshc = &conn->proto.sshc;
+
+#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
+ if(sshc->state != nowstate) {
+ infof(conn->data, "SFTP %p state change from %s to %s\n",
+ (void *)sshc, names[sshc->state], names[nowstate]);
+ }
+#endif
+
+ sshc->state = nowstate;
+}
+
+/* figure out the path to work with in this particular request */
+static CURLcode ssh_getworkingpath(struct connectdata *conn,
+ char *homedir, /* when SFTP is used */
+ char **path) /* returns the allocated
+ real path to work with */
+{
+ struct SessionHandle *data = conn->data;
+ char *real_path = NULL;
+ char *working_path;
+ int working_path_len;
+
+ working_path = curl_easy_unescape(data, data->state.path, 0,
+ &working_path_len);
+ if(!working_path)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Check for /~/ , indicating relative to the user's home directory */
+ if(conn->handler->protocol & CURLPROTO_SCP) {
+ real_path = malloc(working_path_len+1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if((working_path_len > 3) && (!memcmp(working_path, "/~/", 3)))
+ /* It is referenced to the home directory, so strip the leading '/~/' */
+ memcpy(real_path, working_path+3, 4 + working_path_len-3);
+ else
+ memcpy(real_path, working_path, 1 + working_path_len);
+ }
+ else if(conn->handler->protocol & CURLPROTO_SFTP) {
+ if((working_path_len > 1) && (working_path[1] == '~')) {
+ size_t homelen = strlen(homedir);
+ real_path = malloc(homelen + working_path_len + 1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* It is referenced to the home directory, so strip the
+ leading '/' */
+ memcpy(real_path, homedir, homelen);
+ real_path[homelen] = '/';
+ real_path[homelen+1] = '\0';
+ if(working_path_len > 3) {
+ memcpy(real_path+homelen+1, working_path + 3,
+ 1 + working_path_len -3);
+ }
+ }
+ else {
+ real_path = malloc(working_path_len+1);
+ if(real_path == NULL) {
+ free(working_path);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ memcpy(real_path, working_path, 1+working_path_len);
+ }
+ }
+
+ free(working_path);
+
+ /* store the pointer for the caller to receive */
+ *path = real_path;
+
+ return CURLE_OK;
+}
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+static int sshkeycallback(CURL *easy,
+ const struct curl_khkey *knownkey, /* known */
+ const struct curl_khkey *foundkey, /* found */
+ enum curl_khmatch match,
+ void *clientp)
+{
+ (void)easy;
+ (void)knownkey;
+ (void)foundkey;
+ (void)clientp;
+
+ /* we only allow perfect matches, and we reject everything else */
+ return (match != CURLKHMATCH_OK)?CURLKHSTAT_REJECT:CURLKHSTAT_FINE;
+}
+#endif
+
+/*
+ * Earlier libssh2 versions didn't have the ability to seek to 64bit positions
+ * with 32bit size_t.
+ */
+#ifdef HAVE_LIBSSH2_SFTP_SEEK64
+#define SFTP_SEEK(x,y) libssh2_sftp_seek64(x, (libssh2_uint64_t)y)
+#else
+#define SFTP_SEEK(x,y) libssh2_sftp_seek(x, (size_t)y)
+#endif
+
+/*
+ * Earlier libssh2 versions didn't do SCP properly beyond 32bit sizes on 32bit
+ * architectures so we check of the necessary function is present.
+ */
+#ifndef HAVE_LIBSSH2_SCP_SEND64
+#define SCP_SEND(a,b,c,d) libssh2_scp_send_ex(a, b, (int)(c), (size_t)d, 0, 0)
+#else
+#define SCP_SEND(a,b,c,d) libssh2_scp_send64(a, b, (int)(c), \
+ (libssh2_uint64_t)d, 0, 0)
+#endif
+
+/*
+ * libssh2 1.2.8 fixed the problem with 32bit ints used for sockets on win64.
+ */
+#ifdef HAVE_LIBSSH2_SESSION_HANDSHAKE
+#define libssh2_session_startup(x,y) libssh2_session_handshake(x,y)
+#endif
+
+static CURLcode ssh_knownhost(struct connectdata *conn)
+{
+ CURLcode result = CURLE_OK;
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ struct SessionHandle *data = conn->data;
+
+ if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ /* we're asked to verify the host against a file */
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ int rc;
+ int keytype;
+ size_t keylen;
+ const char *remotekey = libssh2_session_hostkey(sshc->ssh_session,
+ &keylen, &keytype);
+ int keycheck = LIBSSH2_KNOWNHOST_CHECK_FAILURE;
+ int keybit = 0;
+
+ if(remotekey) {
+ /*
+ * A subject to figure out is what host name we need to pass in here.
+ * What host name does OpenSSH store in its file if an IDN name is
+ * used?
+ */
+ struct libssh2_knownhost *host;
+ enum curl_khmatch keymatch;
+ curl_sshkeycallback func =
+ data->set.ssh_keyfunc?data->set.ssh_keyfunc:sshkeycallback;
+ struct curl_khkey knownkey;
+ struct curl_khkey *knownkeyp = NULL;
+ struct curl_khkey foundkey;
+
+ keybit = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ LIBSSH2_KNOWNHOST_KEY_SSHRSA:LIBSSH2_KNOWNHOST_KEY_SSHDSS;
+
+ keycheck = libssh2_knownhost_check(sshc->kh,
+ conn->host.name,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit,
+ &host);
+
+ infof(data, "SSH host check: %d, key: %s\n", keycheck,
+ (keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH)?
+ host->key:"<none>");
+
+ /* setup 'knownkey' */
+ if(keycheck <= LIBSSH2_KNOWNHOST_CHECK_MISMATCH) {
+ knownkey.key = host->key;
+ knownkey.len = 0;
+ knownkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+ knownkeyp = &knownkey;
+ }
+
+ /* setup 'foundkey' */
+ foundkey.key = remotekey;
+ foundkey.len = keylen;
+ foundkey.keytype = (keytype == LIBSSH2_HOSTKEY_TYPE_RSA)?
+ CURLKHTYPE_RSA : CURLKHTYPE_DSS;
+
+ /*
+ * if any of the LIBSSH2_KNOWNHOST_CHECK_* defines and the
+ * curl_khmatch enum are ever modified, we need to introduce a
+ * translation table here!
+ */
+ keymatch = (enum curl_khmatch)keycheck;
+
+ /* Ask the callback how to behave */
+ rc = func(data, knownkeyp, /* from the knownhosts file */
+ &foundkey, /* from the remote host */
+ keymatch, data->set.ssh_keyfunc_userp);
+ }
+ else
+ /* no remotekey means failure! */
+ rc = CURLKHSTAT_REJECT;
+
+ switch(rc) {
+ default: /* unknown return codes will equal reject */
+ case CURLKHSTAT_REJECT:
+ state(conn, SSH_SESSION_FREE);
+ case CURLKHSTAT_DEFER:
+ /* DEFER means bail out but keep the SSH_HOSTKEY state */
+ result = sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ break;
+ case CURLKHSTAT_FINE:
+ case CURLKHSTAT_FINE_ADD_TO_FILE:
+ /* proceed */
+ if(keycheck != LIBSSH2_KNOWNHOST_CHECK_MATCH) {
+ /* the found host+key didn't match but has been told to be fine
+ anyway so we add it in memory */
+ int addrc = libssh2_knownhost_add(sshc->kh,
+ conn->host.name, NULL,
+ remotekey, keylen,
+ LIBSSH2_KNOWNHOST_TYPE_PLAIN|
+ LIBSSH2_KNOWNHOST_KEYENC_RAW|
+ keybit, NULL);
+ if(addrc)
+ infof(data, "Warning adding the known host %s failed!\n",
+ conn->host.name);
+ else if(rc == CURLKHSTAT_FINE_ADD_TO_FILE) {
+ /* now we write the entire in-memory list of known hosts to the
+ known_hosts file */
+ int wrc =
+ libssh2_knownhost_writefile(sshc->kh,
+ data->set.str[STRING_SSH_KNOWNHOSTS],
+ LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+ if(wrc) {
+ infof(data, "Warning, writing %s failed!\n",
+ data->set.str[STRING_SSH_KNOWNHOSTS]);
+ }
+ }
+ }
+ break;
+ }
+ }
+#else /* HAVE_LIBSSH2_KNOWNHOST_API */
+ (void)conn;
+#endif
+ return result;
+}
+
+static CURLcode ssh_check_fingerprint(struct connectdata *conn)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ struct SessionHandle *data = conn->data;
+ const char *pubkey_md5 = data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5];
+ char md5buffer[33];
+ int i;
+
+ const char *fingerprint = libssh2_hostkey_hash(sshc->ssh_session,
+ LIBSSH2_HOSTKEY_HASH_MD5);
+
+ if(fingerprint) {
+ /* The fingerprint points to static storage (!), don't free() it. */
+ for(i = 0; i < 16; i++)
+ snprintf(&md5buffer[i*2], 3, "%02x", (unsigned char) fingerprint[i]);
+ infof(data, "SSH MD5 fingerprint: %s\n", md5buffer);
+ }
+
+ /* Before we authenticate we check the hostkey's MD5 fingerprint
+ * against a known fingerprint, if available.
+ */
+ if(pubkey_md5 && strlen(pubkey_md5) == 32) {
+ if(!fingerprint || !strequal(md5buffer, pubkey_md5)) {
+ if(fingerprint)
+ failf(data,
+ "Denied establishing ssh session: mismatch md5 fingerprint. "
+ "Remote %s is not equal to %s", md5buffer, pubkey_md5);
+ else
+ failf(data,
+ "Denied establishing ssh session: md5 fingerprint not available");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_PEER_FAILED_VERIFICATION;
+ return sshc->actualcode;
+ }
+ else {
+ infof(data, "MD5 checksum match!\n");
+ /* as we already matched, we skip the check for known hosts */
+ return CURLE_OK;
+ }
+ }
+ else
+ return ssh_knownhost(conn);
+}
+
+/*
+ * ssh_statemach_act() runs the SSH state machine as far as it can without
+ * blocking and without reaching the end. The data the pointer 'block' points
+ * to will be set to TRUE if the libssh2 function returns LIBSSH2_ERROR_EAGAIN
+ * meaning it wants to be called again when the socket is ready
+ */
+
+static CURLcode ssh_statemach_act(struct connectdata *conn, bool *block)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ struct SSHPROTO *sftp_scp = data->req.protop;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ char *new_readdir_line;
+ int rc = LIBSSH2_ERROR_NONE;
+ int err;
+ int seekerr = CURL_SEEKFUNC_OK;
+ *block = 0; /* we're not blocking by default */
+
+ do {
+
+ switch(sshc->state) {
+ case SSH_INIT:
+ sshc->secondCreateDirs = 0;
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_OK;
+
+ /* Set libssh2 to non-blocking, since everything internally is
+ non-blocking */
+ libssh2_session_set_blocking(sshc->ssh_session, 0);
+
+ state(conn, SSH_S_STARTUP);
+ /* fall-through */
+
+ case SSH_S_STARTUP:
+ rc = libssh2_session_startup(sshc->ssh_session, (int)sock);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ failf(data, "Failure establishing ssh session");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+
+ state(conn, SSH_HOSTKEY);
+
+ /* fall-through */
+ case SSH_HOSTKEY:
+ /*
+ * Before we authenticate we should check the hostkey's fingerprint
+ * against our known hosts. How that is handled (reading from file,
+ * whatever) is up to us.
+ */
+ result = ssh_check_fingerprint(conn);
+ if(result == CURLE_OK)
+ state(conn, SSH_AUTHLIST);
+ break;
+
+ case SSH_AUTHLIST:
+ /*
+ * Figure out authentication methods
+ * NB: As soon as we have provided a username to an openssh server we
+ * must never change it later. Thus, always specify the correct username
+ * here, even though the libssh2 docs kind of indicate that it should be
+ * possible to get a 'generic' list (not user-specific) of authentication
+ * methods, presumably with a blank username. That won't work in my
+ * experience.
+ * So always specify it here.
+ */
+ sshc->authlist = libssh2_userauth_list(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(strlen(conn->user)));
+
+ if(!sshc->authlist) {
+ if((err = libssh2_session_last_errno(sshc->ssh_session)) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(err);
+ break;
+ }
+ }
+ infof(data, "SSH authentication methods available: %s\n",
+ sshc->authlist);
+
+ state(conn, SSH_AUTH_PKEY_INIT);
+ break;
+
+ case SSH_AUTH_PKEY_INIT:
+ /*
+ * Check the supported auth types in the order I feel is most secure
+ * with the requested type of authentication
+ */
+ sshc->authed = FALSE;
+
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PUBLICKEY) &&
+ (strstr(sshc->authlist, "publickey") != NULL)) {
+ char *home = NULL;
+ bool rsa_pub_empty_but_ok = FALSE;
+
+ sshc->rsa_pub = sshc->rsa = NULL;
+
+ /* To ponder about: should really the lib be messing about with the
+ HOME environment variable etc? */
+ home = curl_getenv("HOME");
+
+ if(data->set.str[STRING_SSH_PUBLIC_KEY] &&
+ !*data->set.str[STRING_SSH_PUBLIC_KEY])
+ rsa_pub_empty_but_ok = true;
+ else if(data->set.str[STRING_SSH_PUBLIC_KEY])
+ sshc->rsa_pub = aprintf("%s", data->set.str[STRING_SSH_PUBLIC_KEY]);
+ else if(home)
+ sshc->rsa_pub = aprintf("%s/.ssh/id_dsa.pub", home);
+ else
+ /* as a final resort, try current dir! */
+ sshc->rsa_pub = strdup("id_dsa.pub");
+
+ if(!rsa_pub_empty_but_ok && (sshc->rsa_pub == NULL)) {
+ Curl_safefree(home);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ if(data->set.str[STRING_SSH_PRIVATE_KEY])
+ sshc->rsa = aprintf("%s", data->set.str[STRING_SSH_PRIVATE_KEY]);
+ else if(home)
+ sshc->rsa = aprintf("%s/.ssh/id_dsa", home);
+ else
+ /* as a final resort, try current dir! */
+ sshc->rsa = strdup("id_dsa");
+
+ if(sshc->rsa == NULL) {
+ Curl_safefree(home);
+ Curl_safefree(sshc->rsa_pub);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ sshc->passphrase = data->set.str[STRING_KEY_PASSWD];
+ if(!sshc->passphrase)
+ sshc->passphrase = "";
+
+ Curl_safefree(home);
+
+ infof(data, "Using ssh public key file %s\n", sshc->rsa_pub);
+ infof(data, "Using ssh private key file %s\n", sshc->rsa);
+
+ state(conn, SSH_AUTH_PKEY);
+ }
+ else {
+ state(conn, SSH_AUTH_PASS_INIT);
+ }
+ break;
+
+ case SSH_AUTH_PKEY:
+ /* The function below checks if the files exists, no need to stat() here.
+ */
+ rc = libssh2_userauth_publickey_fromfile_ex(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(
+ strlen(conn->user)),
+ sshc->rsa_pub,
+ sshc->rsa, sshc->passphrase);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+
+ if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized SSH public key authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ char *err_msg;
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ infof(data, "SSH public key authentication failed: %s\n", err_msg);
+ state(conn, SSH_AUTH_PASS_INIT);
+ }
+ break;
+
+ case SSH_AUTH_PASS_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_PASSWORD) &&
+ (strstr(sshc->authlist, "password") != NULL)) {
+ state(conn, SSH_AUTH_PASS);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ }
+ break;
+
+ case SSH_AUTH_PASS:
+ rc = libssh2_userauth_password_ex(sshc->ssh_session, conn->user,
+ curlx_uztoui(strlen(conn->user)),
+ conn->passwd,
+ curlx_uztoui(strlen(conn->passwd)),
+ NULL);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized password authentication\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else {
+ state(conn, SSH_AUTH_HOST_INIT);
+ }
+ break;
+
+ case SSH_AUTH_HOST_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_HOST) &&
+ (strstr(sshc->authlist, "hostbased") != NULL)) {
+ state(conn, SSH_AUTH_HOST);
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT_INIT);
+ }
+ break;
+
+ case SSH_AUTH_HOST:
+ state(conn, SSH_AUTH_AGENT_INIT);
+ break;
+
+ case SSH_AUTH_AGENT_INIT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_AGENT)
+ && (strstr(sshc->authlist, "publickey") != NULL)) {
+
+ /* Connect to the ssh-agent */
+ /* The agent could be shared by a curl thread i believe
+ but nothing obvious as keys can be added/removed at any time */
+ if(!sshc->ssh_agent) {
+ sshc->ssh_agent = libssh2_agent_init(sshc->ssh_session);
+ if(!sshc->ssh_agent) {
+ infof(data, "Could not create agent object\n");
+
+ state(conn, SSH_AUTH_KEY_INIT);
+ }
+ }
+
+ rc = libssh2_agent_connect(sshc->ssh_agent);
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+ if(rc < 0) {
+ infof(data, "Failure connecting to agent\n");
+ state(conn, SSH_AUTH_KEY_INIT);
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT_LIST);
+ }
+ }
+ else
+#endif /* HAVE_LIBSSH2_AGENT_API */
+ state(conn, SSH_AUTH_KEY_INIT);
+ break;
+
+ case SSH_AUTH_AGENT_LIST:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ rc = libssh2_agent_list_identities(sshc->ssh_agent);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+ if(rc < 0) {
+ infof(data, "Failure requesting identities to agent\n");
+ state(conn, SSH_AUTH_KEY_INIT);
+ }
+ else {
+ state(conn, SSH_AUTH_AGENT);
+ sshc->sshagent_prev_identity = NULL;
+ }
+#endif
+ break;
+
+ case SSH_AUTH_AGENT:
+#ifdef HAVE_LIBSSH2_AGENT_API
+ /* as prev_identity evolves only after an identity user auth finished we
+ can safely request it again as long as EAGAIN is returned here or by
+ libssh2_agent_userauth */
+ rc = libssh2_agent_get_identity(sshc->ssh_agent,
+ &sshc->sshagent_identity,
+ sshc->sshagent_prev_identity);
+ if(rc == LIBSSH2_ERROR_EAGAIN)
+ break;
+
+ if(rc == 0) {
+ rc = libssh2_agent_userauth(sshc->ssh_agent, conn->user,
+ sshc->sshagent_identity);
+
+ if(rc < 0) {
+ if(rc != LIBSSH2_ERROR_EAGAIN) {
+ /* tried and failed? go to next identity */
+ sshc->sshagent_prev_identity = sshc->sshagent_identity;
+ }
+ break;
+ }
+ }
+
+ if(rc < 0)
+ infof(data, "Failure requesting identities to agent\n");
+ else if(rc == 1)
+ infof(data, "No identity would match\n");
+
+ if(rc == LIBSSH2_ERROR_NONE) {
+ sshc->authed = TRUE;
+ infof(data, "Agent based authentication successful\n");
+ state(conn, SSH_AUTH_DONE);
+ }
+ else
+ state(conn, SSH_AUTH_KEY_INIT);
+#endif
+ break;
+
+ case SSH_AUTH_KEY_INIT:
+ if((data->set.ssh_auth_types & CURLSSH_AUTH_KEYBOARD)
+ && (strstr(sshc->authlist, "keyboard-interactive") != NULL)) {
+ state(conn, SSH_AUTH_KEY);
+ }
+ else {
+ state(conn, SSH_AUTH_DONE);
+ }
+ break;
+
+ case SSH_AUTH_KEY:
+ /* Authentication failed. Continue with keyboard-interactive now. */
+ rc = libssh2_userauth_keyboard_interactive_ex(sshc->ssh_session,
+ conn->user,
+ curlx_uztoui(
+ strlen(conn->user)),
+ &kbd_callback);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc == 0) {
+ sshc->authed = TRUE;
+ infof(data, "Initialized keyboard interactive authentication\n");
+ }
+ state(conn, SSH_AUTH_DONE);
+ break;
+
+ case SSH_AUTH_DONE:
+ if(!sshc->authed) {
+ failf(data, "Authentication failure");
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_LOGIN_DENIED;
+ break;
+ }
+
+ /*
+ * At this point we have an authenticated ssh session.
+ */
+ infof(data, "Authentication complete\n");
+
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSH is connected */
+
+ conn->sockfd = sock;
+ conn->writesockfd = CURL_SOCKET_BAD;
+
+ if(conn->handler->protocol == CURLPROTO_SFTP) {
+ state(conn, SSH_SFTP_INIT);
+ break;
+ }
+ infof(data, "SSH CONNECT phase done\n");
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_INIT:
+ /*
+ * Start the libssh2 sftp session
+ */
+ sshc->sftp_session = libssh2_sftp_init(sshc->ssh_session);
+ if(!sshc->sftp_session) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ char *err_msg;
+
+ (void)libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0);
+ failf(data, "Failure initializing sftp session: %s", err_msg);
+ state(conn, SSH_SESSION_FREE);
+ sshc->actualcode = CURLE_FAILED_INIT;
+ break;
+ }
+ }
+ state(conn, SSH_SFTP_REALPATH);
+ break;
+
+ case SSH_SFTP_REALPATH:
+ {
+ char tempHome[PATH_MAX];
+
+ /*
+ * Get the "home" directory
+ */
+ rc = sftp_libssh2_realpath(sshc->sftp_session, ".",
+ tempHome, PATH_MAX-1);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc > 0) {
+ /* It seems that this string is not always NULL terminated */
+ tempHome[rc] = '\0';
+ sshc->homedir = strdup(tempHome);
+ if(!sshc->homedir) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ conn->data->state.most_recent_ftp_entrypath = sshc->homedir;
+ }
+ else {
+ /* Return the error type */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ DEBUGF(infof(data, "error = %d makes libcurl = %d\n",
+ err, (int)result));
+ state(conn, SSH_STOP);
+ break;
+ }
+ }
+ /* This is the last step in the SFTP connect phase. Do note that while
+ we get the homedir here, we get the "workingpath" in the DO action
+ since the homedir will remain the same between request but the
+ working path will not. */
+ DEBUGF(infof(data, "SSH CONNECT phase done\n"));
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_QUOTE_INIT:
+
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ if(data->set.quote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.quote;
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ break;
+
+ case SSH_SFTP_POSTQUOTE_INIT:
+ if(data->set.postquote) {
+ infof(data, "Sending quote commands\n");
+ sshc->quote_item = data->set.postquote;
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SFTP_QUOTE:
+ /* Send any quote commands */
+ {
+ const char *cp;
+
+ /*
+ * Support some of the "FTP" commands
+ */
+ char *cmd = sshc->quote_item->data;
+ sshc->acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal SFTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ sshc->acceptfail = TRUE;
+ }
+
+ if(curl_strequal("pwd", cmd)) {
+ /* output debug output if that is requested */
+ char *tmp = aprintf("257 \"%s\" is current directory.\n",
+ sftp_scp->path);
+ if(!tmp) {
+ result = CURLE_OUT_OF_MEMORY;
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ break;
+ }
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_HEADER_OUT, (char *)"PWD\n", 4, conn);
+ Curl_debug(data, CURLINFO_HEADER_IN, tmp, strlen(tmp), conn);
+ }
+ /* this sends an FTP-like "header" to the header callback so that the
+ current directory can be read very similar to how it is read when
+ using ordinary FTP. */
+ result = Curl_client_write(conn, CLIENTWRITE_HEADER, tmp, strlen(tmp));
+ free(tmp);
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+ }
+ else if(cmd) {
+ /*
+ * the arguments following the command must be separated from the
+ * command with a space so we can check for it unconditionally
+ */
+ cp = strchr(cmd, ' ');
+ if(cp == NULL) {
+ failf(data, "Syntax error in SFTP command. Supply parameter(s)!");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+
+ /*
+ * also, every command takes at least one argument so we get that
+ * first argument right now
+ */
+ result = get_pathname(&cp, &sshc->quote_path1);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error: Bad first parameter");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+
+ /*
+ * SFTP is a binary protocol, so we don't send text commands to
+ * the server. Instead, we scan for commands for commands used by
+ * OpenSSH's sftp program and call the appropriate libssh2
+ * functions.
+ */
+ if(curl_strnequal(cmd, "chgrp ", 6) ||
+ curl_strnequal(cmd, "chmod ", 6) ||
+ curl_strnequal(cmd, "chown ", 6) ) {
+ /* attribute change */
+
+ /* sshc->quote_path1 contains the mode to set */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in chgrp/chmod/chown: "
+ "Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ memset(&sshc->quote_attrs, 0, sizeof(LIBSSH2_SFTP_ATTRIBUTES));
+ state(conn, SSH_SFTP_QUOTE_STAT);
+ break;
+ }
+ else if(curl_strnequal(cmd, "ln ", 3) ||
+ curl_strnequal(cmd, "symlink ", 8)) {
+ /* symbolic linking */
+ /* sshc->quote_path1 is the source */
+ /* get the destination */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data,
+ "Syntax error in ln/symlink: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_SYMLINK);
+ break;
+ }
+ else if(curl_strnequal(cmd, "mkdir ", 6)) {
+ /* create dir */
+ state(conn, SSH_SFTP_QUOTE_MKDIR);
+ break;
+ }
+ else if(curl_strnequal(cmd, "rename ", 7)) {
+ /* rename file */
+ /* first param is the source path */
+ /* second param is the dest. path */
+ result = get_pathname(&cp, &sshc->quote_path2);
+ if(result) {
+ if(result == CURLE_OUT_OF_MEMORY)
+ failf(data, "Out of memory");
+ else
+ failf(data, "Syntax error in rename: Bad second parameter");
+ Curl_safefree(sshc->quote_path1);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = result;
+ break;
+ }
+ state(conn, SSH_SFTP_QUOTE_RENAME);
+ break;
+ }
+ else if(curl_strnequal(cmd, "rmdir ", 6)) {
+ /* delete dir */
+ state(conn, SSH_SFTP_QUOTE_RMDIR);
+ break;
+ }
+ else if(curl_strnequal(cmd, "rm ", 3)) {
+ state(conn, SSH_SFTP_QUOTE_UNLINK);
+ break;
+ }
+
+ failf(data, "Unknown SFTP command");
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ if(!sshc->quote_item) {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ break;
+
+ case SSH_SFTP_NEXT_QUOTE:
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+
+ sshc->quote_item = sshc->quote_item->next;
+
+ if(sshc->quote_item) {
+ state(conn, SSH_SFTP_QUOTE);
+ }
+ else {
+ if(sshc->nextstate != SSH_NO_STATE) {
+ state(conn, sshc->nextstate);
+ sshc->nextstate = SSH_NO_STATE;
+ }
+ else {
+ state(conn, SSH_SFTP_TRANS_INIT);
+ }
+ }
+ break;
+
+ case SSH_SFTP_QUOTE_STAT:
+ {
+ char *cmd = sshc->quote_item->data;
+ sshc->acceptfail = FALSE;
+
+ /* if a command starts with an asterisk, which a legal SFTP command never
+ can, the command will be allowed to fail without it causing any
+ aborts or cancels etc. It will cause libcurl to act as if the command
+ is successful, whatever the server reponds. */
+
+ if(cmd[0] == '*') {
+ cmd++;
+ sshc->acceptfail = TRUE;
+ }
+
+ if(!curl_strnequal(cmd, "chmod", 5)) {
+ /* Since chown and chgrp only set owner OR group but libssh2 wants to
+ * set them both at once, we need to obtain the current ownership
+ * first. This takes an extra protocol round trip.
+ */
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_STAT,
+ &sshc->quote_attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) { /* get those attributes */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Attempt to get SFTP stats failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+
+ /* Now set the new attributes... */
+ if(curl_strnequal(cmd, "chgrp", 5)) {
+ sshc->quote_attrs.gid = strtoul(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.gid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+ !sshc->acceptfail) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chgrp gid not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ else if(curl_strnequal(cmd, "chmod", 5)) {
+ sshc->quote_attrs.permissions = strtoul(sshc->quote_path1, NULL, 8);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_PERMISSIONS;
+ /* permissions are octal */
+ if(sshc->quote_attrs.permissions == 0 &&
+ !ISDIGIT(sshc->quote_path1[0])) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chmod permissions not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+ else if(curl_strnequal(cmd, "chown", 5)) {
+ sshc->quote_attrs.uid = strtoul(sshc->quote_path1, NULL, 10);
+ sshc->quote_attrs.flags = LIBSSH2_SFTP_ATTR_UIDGID;
+ if(sshc->quote_attrs.uid == 0 && !ISDIGIT(sshc->quote_path1[0]) &&
+ !sshc->acceptfail) {
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Syntax error: chown uid not a number");
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ }
+
+ /* Now send the completed structure... */
+ state(conn, SSH_SFTP_QUOTE_SETSTAT);
+ break;
+ }
+
+ case SSH_SFTP_QUOTE_SETSTAT:
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_SETSTAT,
+ &sshc->quote_attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "Attempt to set SFTP stats failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_SYMLINK:
+ rc = libssh2_sftp_symlink_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_SYMLINK);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "symlink command failed: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_MKDIR:
+ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ data->set.new_directory_perms);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "mkdir command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_RENAME:
+ rc = libssh2_sftp_rename_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)),
+ sshc->quote_path2,
+ curlx_uztoui(strlen(sshc->quote_path2)),
+ LIBSSH2_SFTP_RENAME_OVERWRITE |
+ LIBSSH2_SFTP_RENAME_ATOMIC |
+ LIBSSH2_SFTP_RENAME_NATIVE);
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+ failf(data, "rename command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_RMDIR:
+ rc = libssh2_sftp_rmdir_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)));
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "rmdir command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_QUOTE_UNLINK:
+ rc = libssh2_sftp_unlink_ex(sshc->sftp_session, sshc->quote_path1,
+ curlx_uztoui(strlen(sshc->quote_path1)));
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc != 0 && !sshc->acceptfail) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ Curl_safefree(sshc->quote_path1);
+ failf(data, "rm command failed: %s", sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->nextstate = SSH_NO_STATE;
+ sshc->actualcode = CURLE_QUOTE_ERROR;
+ break;
+ }
+ state(conn, SSH_SFTP_NEXT_QUOTE);
+ break;
+
+ case SSH_SFTP_TRANS_INIT:
+ if(data->set.upload)
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ else {
+ if(data->set.opt_no_body)
+ state(conn, SSH_STOP);
+ else if(sftp_scp->path[strlen(sftp_scp->path)-1] == '/')
+ state(conn, SSH_SFTP_READDIR_INIT);
+ else
+ state(conn, SSH_SFTP_DOWNLOAD_INIT);
+ }
+ break;
+
+ case SSH_SFTP_UPLOAD_INIT:
+ {
+ unsigned long flags;
+ /*
+ * NOTE!!! libssh2 requires that the destination path is a full path
+ * that includes the destination file and name OR ends in a "/"
+ * If this is not done the destination file will be named the
+ * same name as the last directory in the path.
+ */
+
+ if(data->state.resume_from != 0) {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+ if(data->state.resume_from < 0) {
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_SFTP_STAT, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ data->state.resume_from = 0;
+ }
+ else {
+ curl_off_t size = attrs.filesize;
+ if(size < 0) {
+ failf(data, "Bad file size (%" FORMAT_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ data->state.resume_from = attrs.filesize;
+ }
+ }
+ }
+
+ if(data->set.ftp_append)
+ /* Try to open for append, but create if nonexisting */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_APPEND;
+ else if(data->state.resume_from > 0)
+ /* If we have restart position then open for append */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_APPEND;
+ else
+ /* Clear file before writing (normal behaviour) */
+ flags = LIBSSH2_FXF_WRITE|LIBSSH2_FXF_CREAT|LIBSSH2_FXF_TRUNC;
+
+ sshc->sftp_handle =
+ libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ flags, data->set.new_file_perms,
+ LIBSSH2_SFTP_OPENFILE);
+
+ if(!sshc->sftp_handle) {
+ rc = libssh2_session_last_errno(sshc->ssh_session);
+
+ if(LIBSSH2_ERROR_EAGAIN == rc)
+ break;
+ else {
+ if(LIBSSH2_ERROR_SFTP_PROTOCOL == rc)
+ /* only when there was an SFTP protocol error can we extract
+ the sftp error! */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ else
+ err = -1; /* not an sftp error at all */
+
+ if(sshc->secondCreateDirs) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = err>= LIBSSH2_FX_OK?
+ sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ failf(data, "Creating the dir/file failed: %s",
+ sftp_libssh2_strerror(err));
+ break;
+ }
+ else if(((err == LIBSSH2_FX_NO_SUCH_FILE) ||
+ (err == LIBSSH2_FX_FAILURE) ||
+ (err == LIBSSH2_FX_NO_SUCH_PATH)) &&
+ (data->set.ftp_create_missing_dirs &&
+ (strlen(sftp_scp->path) > 1))) {
+ /* try to create the path remotely */
+ sshc->secondCreateDirs = 1;
+ state(conn, SSH_SFTP_CREATE_DIRS_INIT);
+ break;
+ }
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = err>= LIBSSH2_FX_OK?
+ sftp_libssh2_error_to_CURLE(err):CURLE_SSH;
+ if(!sshc->actualcode) {
+ /* Sometimes, for some reason libssh2_sftp_last_error() returns
+ zero even though libssh2_sftp_open() failed previously! We need
+ to work around that! */
+ sshc->actualcode = CURLE_SSH;
+ err=-1;
+ }
+ failf(data, "Upload failed: %s (%d/%d)",
+ err>= LIBSSH2_FX_OK?sftp_libssh2_strerror(err):"ssh error",
+ err, rc);
+ break;
+ }
+ }
+
+ /* If we have restart point then we need to seek to the correct
+ position. */
+ if(data->state.resume_from > 0) {
+ /* Let's read off the proper amount of bytes from the input. */
+ if(conn->seek_func) {
+ seekerr = conn->seek_func(conn->seek_client, data->state.resume_from,
+ SEEK_SET);
+ }
+
+ if(seekerr != CURL_SEEKFUNC_OK) {
+
+ if(seekerr != CURL_SEEKFUNC_CANTSEEK) {
+ failf(data, "Could not seek stream");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ /* seekerr == CURL_SEEKFUNC_CANTSEEK (can't seek to offset) */
+ else {
+ curl_off_t passed=0;
+ do {
+ size_t readthisamountnow =
+ (data->state.resume_from - passed > CURL_OFF_T_C(BUFSIZE)) ?
+ BUFSIZE : curlx_sotouz(data->state.resume_from - passed);
+
+ size_t actuallyread =
+ conn->fread_func(data->state.buffer, 1, readthisamountnow,
+ conn->fread_in);
+
+ passed += actuallyread;
+ if((actuallyread == 0) || (actuallyread > readthisamountnow)) {
+ /* this checks for greater-than only to make sure that the
+ CURL_READFUNC_ABORT return code still aborts */
+ failf(data, "Failed to read data");
+ return CURLE_FTP_COULDNT_USE_REST;
+ }
+ } while(passed < data->state.resume_from);
+ }
+ }
+
+ /* now, decrease the size of the read */
+ if(data->set.infilesize > 0) {
+ data->set.infilesize -= data->state.resume_from;
+ data->req.size = data->set.infilesize;
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+ }
+
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
+ if(data->set.infilesize > 0) {
+ data->req.size = data->set.infilesize;
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+ }
+ /* upload data */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
+
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ /* store this original bitmask setup to use later on if we can't
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
+
+ /* we want to use the _sending_ function even when the socket turns
+ out readable as the underlying libssh2 sftp send function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_OUT;
+
+ /* since we don't really wait for anything at this point, we want the
+ state machine to move on as soon as possible so we set a very short
+ timeout here */
+ Curl_expire(data, 1);
+
+ state(conn, SSH_STOP);
+ }
+ break;
+ }
+
+ case SSH_SFTP_CREATE_DIRS_INIT:
+ if(strlen(sftp_scp->path) > 1) {
+ sshc->slash_pos = sftp_scp->path + 1; /* ignore the leading '/' */
+ state(conn, SSH_SFTP_CREATE_DIRS);
+ }
+ else {
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ }
+ break;
+
+ case SSH_SFTP_CREATE_DIRS:
+ if((sshc->slash_pos = strchr(sshc->slash_pos, '/')) != NULL) {
+ *sshc->slash_pos = 0;
+
+ infof(data, "Creating directory '%s'\n", sftp_scp->path);
+ state(conn, SSH_SFTP_CREATE_DIRS_MKDIR);
+ break;
+ }
+ else {
+ state(conn, SSH_SFTP_UPLOAD_INIT);
+ }
+ break;
+
+ case SSH_SFTP_CREATE_DIRS_MKDIR:
+ /* 'mode' - parameter is preliminary - default to 0644 */
+ rc = libssh2_sftp_mkdir_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ data->set.new_directory_perms);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ *sshc->slash_pos = '/';
+ ++sshc->slash_pos;
+ if(rc == -1) {
+ /*
+ * Abort if failure wasn't that the dir already exists or the
+ * permission was denied (creation might succeed further down the
+ * path) - retry on unspecific FAILURE also
+ */
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ if((err != LIBSSH2_FX_FILE_ALREADY_EXISTS) &&
+ (err != LIBSSH2_FX_FAILURE) &&
+ (err != LIBSSH2_FX_PERMISSION_DENIED)) {
+ result = sftp_libssh2_error_to_CURLE(err);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ }
+ state(conn, SSH_SFTP_CREATE_DIRS);
+ break;
+
+ case SSH_SFTP_READDIR_INIT:
+ /*
+ * This is a directory that we are trying to get, so produce a directory
+ * listing
+ */
+ sshc->sftp_handle = libssh2_sftp_open_ex(sshc->sftp_session,
+ sftp_scp->path,
+ curlx_uztoui(
+ strlen(sftp_scp->path)),
+ 0, 0, LIBSSH2_SFTP_OPENDIR);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ failf(data, "Could not open directory for reading: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ }
+ if((sshc->readdir_filename = malloc(PATH_MAX+1)) == NULL) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ if((sshc->readdir_longentry = malloc(PATH_MAX+1)) == NULL) {
+ Curl_safefree(sshc->readdir_filename);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR);
+ break;
+
+ case SSH_SFTP_READDIR:
+ sshc->readdir_len = libssh2_sftp_readdir_ex(sshc->sftp_handle,
+ sshc->readdir_filename,
+ PATH_MAX,
+ sshc->readdir_longentry,
+ PATH_MAX,
+ &sshc->readdir_attrs);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ if(sshc->readdir_len > 0) {
+ sshc->readdir_filename[sshc->readdir_len] = '\0';
+
+ if(data->set.ftp_list_only) {
+ char *tmpLine;
+
+ tmpLine = aprintf("%s\n", sshc->readdir_filename);
+ if(tmpLine == NULL) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ tmpLine, sshc->readdir_len+1);
+ Curl_safefree(tmpLine);
+
+ if(result) {
+ state(conn, SSH_STOP);
+ break;
+ }
+ /* since this counts what we send to the client, we include the
+ newline in this counter */
+ data->req.bytecount += sshc->readdir_len+1;
+
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_filename,
+ sshc->readdir_len, conn);
+ }
+ }
+ else {
+ sshc->readdir_currLen = (int)strlen(sshc->readdir_longentry);
+ sshc->readdir_totalLen = 80 + sshc->readdir_currLen;
+ sshc->readdir_line = calloc(sshc->readdir_totalLen, 1);
+ if(!sshc->readdir_line) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ memcpy(sshc->readdir_line, sshc->readdir_longentry,
+ sshc->readdir_currLen);
+ if((sshc->readdir_attrs.flags & LIBSSH2_SFTP_ATTR_PERMISSIONS) &&
+ ((sshc->readdir_attrs.permissions & LIBSSH2_SFTP_S_IFMT) ==
+ LIBSSH2_SFTP_S_IFLNK)) {
+ sshc->readdir_linkPath = malloc(PATH_MAX + 1);
+ if(sshc->readdir_linkPath == NULL) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+
+ snprintf(sshc->readdir_linkPath, PATH_MAX, "%s%s", sftp_scp->path,
+ sshc->readdir_filename);
+ state(conn, SSH_SFTP_READDIR_LINK);
+ break;
+ }
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
+ break;
+ }
+ }
+ else if(sshc->readdir_len == 0) {
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_READDIR_DONE);
+ break;
+ }
+ else if(sshc->readdir_len <= 0) {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ failf(data, "Could not open remote file for reading: %s :: %d",
+ sftp_libssh2_strerror(err),
+ libssh2_session_last_errno(sshc->ssh_session));
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ break;
+ }
+ break;
+
+ case SSH_SFTP_READDIR_LINK:
+ sshc->readdir_len =
+ libssh2_sftp_symlink_ex(sshc->sftp_session,
+ sshc->readdir_linkPath,
+ curlx_uztoui(strlen(sshc->readdir_linkPath)),
+ sshc->readdir_filename,
+ PATH_MAX, LIBSSH2_SFTP_READLINK);
+ if(sshc->readdir_len == LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ Curl_safefree(sshc->readdir_linkPath);
+
+ /* get room for the filename and extra output */
+ sshc->readdir_totalLen += 4 + sshc->readdir_len;
+ new_readdir_line = realloc(sshc->readdir_line, sshc->readdir_totalLen);
+ if(!new_readdir_line) {
+ Curl_safefree(sshc->readdir_line);
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ sshc->readdir_line = new_readdir_line;
+
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen,
+ " -> %s",
+ sshc->readdir_filename);
+
+ state(conn, SSH_SFTP_READDIR_BOTTOM);
+ break;
+
+ case SSH_SFTP_READDIR_BOTTOM:
+ sshc->readdir_currLen += snprintf(sshc->readdir_line +
+ sshc->readdir_currLen,
+ sshc->readdir_totalLen -
+ sshc->readdir_currLen, "\n");
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ sshc->readdir_line,
+ sshc->readdir_currLen);
+
+ if(result == CURLE_OK) {
+
+ /* output debug output if that is requested */
+ if(data->set.verbose) {
+ Curl_debug(data, CURLINFO_DATA_OUT, sshc->readdir_line,
+ sshc->readdir_currLen, conn);
+ }
+ data->req.bytecount += sshc->readdir_currLen;
+ }
+ Curl_safefree(sshc->readdir_line);
+ if(result) {
+ state(conn, SSH_STOP);
+ }
+ else
+ state(conn, SSH_SFTP_READDIR);
+ break;
+
+ case SSH_SFTP_READDIR_DONE:
+ if(libssh2_sftp_closedir(sshc->sftp_handle) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ sshc->sftp_handle = NULL;
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_SFTP_DOWNLOAD_INIT:
+ /*
+ * Work on getting the specified file
+ */
+ sshc->sftp_handle =
+ libssh2_sftp_open_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_FXF_READ, data->set.new_file_perms,
+ LIBSSH2_SFTP_OPENFILE);
+ if(!sshc->sftp_handle) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ err = sftp_libssh2_last_error(sshc->sftp_session);
+ failf(data, "Could not open remote file for reading: %s",
+ sftp_libssh2_strerror(err));
+ state(conn, SSH_SFTP_CLOSE);
+ result = sftp_libssh2_error_to_CURLE(err);
+ sshc->actualcode = result?result:CURLE_SSH;
+ break;
+ }
+ }
+ state(conn, SSH_SFTP_DOWNLOAD_STAT);
+ break;
+
+ case SSH_SFTP_DOWNLOAD_STAT:
+ {
+ LIBSSH2_SFTP_ATTRIBUTES attrs;
+
+ rc = libssh2_sftp_stat_ex(sshc->sftp_session, sftp_scp->path,
+ curlx_uztoui(strlen(sftp_scp->path)),
+ LIBSSH2_SFTP_STAT, &attrs);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ /*
+ * libssh2_sftp_open() didn't return an error, so maybe the server
+ * just doesn't support stat()
+ */
+ data->req.size = -1;
+ data->req.maxdownload = -1;
+ }
+ else {
+ curl_off_t size = attrs.filesize;
+
+ if(size < 0) {
+ failf(data, "Bad file size (%" FORMAT_OFF_T ")", size);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ if(conn->data->state.use_range) {
+ curl_off_t from, to;
+ char *ptr;
+ char *ptr2;
+
+ from=curlx_strtoofft(conn->data->state.range, &ptr, 0);
+ while(*ptr && (ISSPACE(*ptr) || (*ptr=='-')))
+ ptr++;
+ to=curlx_strtoofft(ptr, &ptr2, 0);
+ if((ptr == ptr2) /* no "to" value given */
+ || (to >= size)) {
+ to = size - 1;
+ }
+ if(from < 0) {
+ /* from is relative to end of file */
+ from += size;
+ }
+ if(from >= size) {
+ failf(data, "Offset (%"
+ FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+ from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ if(from > to) {
+ from = to;
+ size = 0;
+ }
+ else {
+ size = to - from + 1;
+ }
+
+ SFTP_SEEK(conn->proto.sshc.sftp_handle, from);
+ }
+ data->req.size = size;
+ data->req.maxdownload = size;
+ Curl_pgrsSetDownloadSize(data, size);
+ }
+
+ /* We can resume if we can seek to the resume position */
+ if(data->state.resume_from) {
+ if(data->state.resume_from < 0) {
+ /* We're supposed to download the last abs(from) bytes */
+ if((curl_off_t)attrs.filesize < -data->state.resume_from) {
+ failf(data, "Offset (%"
+ FORMAT_OFF_T ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ /* download from where? */
+ data->state.resume_from += attrs.filesize;
+ }
+ else {
+ if((curl_off_t)attrs.filesize < data->state.resume_from) {
+ failf(data, "Offset (%" FORMAT_OFF_T
+ ") was beyond file size (%" FORMAT_OFF_T ")",
+ data->state.resume_from, attrs.filesize);
+ return CURLE_BAD_DOWNLOAD_RESUME;
+ }
+ }
+ /* Does a completed file need to be seeked and started or closed ? */
+ /* Now store the number of bytes we are expected to download */
+ data->req.size = attrs.filesize - data->state.resume_from;
+ data->req.maxdownload = attrs.filesize - data->state.resume_from;
+ Curl_pgrsSetDownloadSize(data,
+ attrs.filesize - data->state.resume_from);
+ SFTP_SEEK(sshc->sftp_handle, data->state.resume_from);
+ }
+ }
+ /* Setup the actual download */
+ if(data->req.size == 0) {
+ /* no data to transfer */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ infof(data, "File already completely downloaded\n");
+ state(conn, SSH_STOP);
+ break;
+ }
+ else {
+ Curl_setup_transfer(conn, FIRSTSOCKET, data->req.size,
+ FALSE, NULL, -1, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
+
+ /* we want to use the _receiving_ function even when the socket turns
+ out writableable as the underlying libssh2 recv function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_IN;
+ }
+ if(result) {
+ state(conn, SSH_SFTP_CLOSE);
+ sshc->actualcode = result;
+ }
+ else {
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SFTP_CLOSE:
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
+ }
+ if(sftp_scp)
+ Curl_safefree(sftp_scp->path);
+
+ DEBUGF(infof(data, "SFTP DONE done\n"));
+
+ /* Check if nextstate is set and move .nextstate could be POSTQUOTE_INIT
+ After nextstate is executed,the control should come back to
+ SSH_SFTP_CLOSE to pass the correct result back */
+ if(sshc->nextstate != SSH_NO_STATE) {
+ state(conn, sshc->nextstate);
+ sshc->nextstate = SSH_SFTP_CLOSE;
+ }
+ else {
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ }
+ break;
+
+ case SSH_SFTP_SHUTDOWN:
+ /* during times we get here due to a broken transfer and then the
+ sftp_handle might not have been taken down so make sure that is done
+ before we proceed */
+
+ if(sshc->sftp_handle) {
+ rc = libssh2_sftp_close(sshc->sftp_handle);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to close libssh2 file\n");
+ }
+ sshc->sftp_handle = NULL;
+ }
+ if(sshc->sftp_session) {
+ rc = libssh2_sftp_shutdown(sshc->sftp_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to stop libssh2 sftp subsystem\n");
+ }
+ sshc->sftp_session = NULL;
+ }
+
+ Curl_safefree(sshc->homedir);
+ conn->data->state.most_recent_ftp_entrypath = NULL;
+
+ state(conn, SSH_SESSION_DISCONNECT);
+ break;
+
+ case SSH_SCP_TRANS_INIT:
+ result = ssh_getworkingpath(conn, sshc->homedir, &sftp_scp->path);
+ if(result) {
+ sshc->actualcode = result;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ if(data->set.upload) {
+ if(data->set.infilesize < 0) {
+ failf(data, "SCP requires a known file size for upload");
+ sshc->actualcode = CURLE_UPLOAD_FAILED;
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+ }
+ state(conn, SSH_SCP_UPLOAD_INIT);
+ }
+ else {
+ state(conn, SSH_SCP_DOWNLOAD_INIT);
+ }
+ break;
+
+ case SSH_SCP_UPLOAD_INIT:
+ /*
+ * libssh2 requires that the destination path is a full path that
+ * includes the destination file and name OR ends in a "/" . If this is
+ * not done the destination file will be named the same name as the last
+ * directory in the path.
+ */
+ sshc->ssh_channel =
+ SCP_SEND(sshc->ssh_session, sftp_scp->path, data->set.new_file_perms,
+ data->set.infilesize);
+ if(!sshc->ssh_channel) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ int ssh_err;
+ char *err_msg;
+
+ ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0));
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+ }
+
+ /* upload data */
+ Curl_setup_transfer(conn, -1, data->req.size, FALSE, NULL,
+ FIRSTSOCKET, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->sockfd = conn->writesockfd;
+
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
+ }
+ else {
+ /* store this original bitmask setup to use later on if we can't
+ figure out a "real" bitmask */
+ sshc->orig_waitfor = data->req.keepon;
+
+ /* we want to use the _sending_ function even when the socket turns
+ out readable as the underlying libssh2 scp send function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_OUT;
+
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SCP_DOWNLOAD_INIT:
+ {
+ /*
+ * We must check the remote file; if it is a directory no values will
+ * be set in sb
+ */
+ struct stat sb;
+ curl_off_t bytecount;
+
+ /* clear the struct scp recv will fill in */
+ memset(&sb, 0, sizeof(struct stat));
+
+ /* get a fresh new channel from the ssh layer */
+ sshc->ssh_channel = libssh2_scp_recv(sshc->ssh_session,
+ sftp_scp->path, &sb);
+ if(!sshc->ssh_channel) {
+ if(libssh2_session_last_errno(sshc->ssh_session) ==
+ LIBSSH2_ERROR_EAGAIN) {
+ rc = LIBSSH2_ERROR_EAGAIN;
+ break;
+ }
+ else {
+ int ssh_err;
+ char *err_msg;
+
+ ssh_err = (int)(libssh2_session_last_error(sshc->ssh_session,
+ &err_msg, NULL, 0));
+ failf(conn->data, "%s", err_msg);
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = libssh2_session_error_to_CURLE(ssh_err);
+ break;
+ }
+ }
+
+ /* download data */
+ bytecount = (curl_off_t)sb.st_size;
+ data->req.maxdownload = (curl_off_t)sb.st_size;
+ Curl_setup_transfer(conn, FIRSTSOCKET, bytecount, FALSE, NULL, -1, NULL);
+
+ /* not set by Curl_setup_transfer to preserve keepon bits */
+ conn->writesockfd = conn->sockfd;
+
+ /* we want to use the _receiving_ function even when the socket turns
+ out writableable as the underlying libssh2 recv function will deal
+ with both accordingly */
+ conn->cselect_bits = CURL_CSELECT_IN;
+
+ if(result) {
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ sshc->actualcode = result;
+ }
+ else
+ state(conn, SSH_STOP);
+ }
+ break;
+
+ case SSH_SCP_DONE:
+ if(data->set.upload)
+ state(conn, SSH_SCP_SEND_EOF);
+ else
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+
+ case SSH_SCP_SEND_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_send_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Failed to send libssh2 channel EOF\n");
+ }
+ }
+ state(conn, SSH_SCP_WAIT_EOF);
+ break;
+
+ case SSH_SCP_WAIT_EOF:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_eof(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Failed to get channel EOF: %d\n", rc);
+ }
+ }
+ state(conn, SSH_SCP_WAIT_CLOSE);
+ break;
+
+ case SSH_SCP_WAIT_CLOSE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_wait_closed(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc) {
+ infof(data, "Channel failed to close: %d\n", rc);
+ }
+ }
+ state(conn, SSH_SCP_CHANNEL_FREE);
+ break;
+
+ case SSH_SCP_CHANNEL_FREE:
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
+ }
+ DEBUGF(infof(data, "SCP DONE phase complete\n"));
+#if 0 /* PREV */
+ state(conn, SSH_SESSION_DISCONNECT);
+#endif
+ state(conn, SSH_STOP);
+ result = sshc->actualcode;
+ break;
+
+ case SSH_SESSION_DISCONNECT:
+ /* during weird times when we've been prematurely aborted, the channel
+ is still alive when we reach this state and we MUST kill the channel
+ properly first */
+ if(sshc->ssh_channel) {
+ rc = libssh2_channel_free(sshc->ssh_channel);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 scp subsystem\n");
+ }
+ sshc->ssh_channel = NULL;
+ }
+
+ if(sshc->ssh_session) {
+ rc = libssh2_session_disconnect(sshc->ssh_session, "Shutdown");
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to disconnect libssh2 session\n");
+ }
+ }
+
+ Curl_safefree(sshc->homedir);
+ conn->data->state.most_recent_ftp_entrypath = NULL;
+
+ state(conn, SSH_SESSION_FREE);
+ break;
+
+ case SSH_SESSION_FREE:
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ if(sshc->kh) {
+ libssh2_knownhost_free(sshc->kh);
+ sshc->kh = NULL;
+ }
+#endif
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+ if(sshc->ssh_agent) {
+ rc = libssh2_agent_disconnect(sshc->ssh_agent);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to disconnect from libssh2 agent\n");
+ }
+ libssh2_agent_free (sshc->ssh_agent);
+ sshc->ssh_agent = NULL;
+
+ /* NB: there is no need to free identities, they are part of internal
+ agent stuff */
+ sshc->sshagent_identity = NULL;
+ sshc->sshagent_prev_identity = NULL;
+ }
+#endif
+
+ if(sshc->ssh_session) {
+ rc = libssh2_session_free(sshc->ssh_session);
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ break;
+ }
+ else if(rc < 0) {
+ infof(data, "Failed to free libssh2 session\n");
+ }
+ sshc->ssh_session = NULL;
+ }
+
+ /* worst-case scenario cleanup */
+
+ DEBUGASSERT(sshc->ssh_session == NULL);
+ DEBUGASSERT(sshc->ssh_channel == NULL);
+ DEBUGASSERT(sshc->sftp_session == NULL);
+ DEBUGASSERT(sshc->sftp_handle == NULL);
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ DEBUGASSERT(sshc->kh == NULL);
+#endif
+#ifdef HAVE_LIBSSH2_AGENT_API
+ DEBUGASSERT(sshc->ssh_agent == NULL);
+#endif
+
+ Curl_safefree(sshc->rsa_pub);
+ Curl_safefree(sshc->rsa);
+
+ Curl_safefree(sshc->quote_path1);
+ Curl_safefree(sshc->quote_path2);
+
+ Curl_safefree(sshc->homedir);
+
+ Curl_safefree(sshc->readdir_filename);
+ Curl_safefree(sshc->readdir_longentry);
+ Curl_safefree(sshc->readdir_line);
+ Curl_safefree(sshc->readdir_linkPath);
+
+ /* the code we are about to return */
+ result = sshc->actualcode;
+
+ memset(sshc, 0, sizeof(struct ssh_conn));
+
+ conn->bits.close = TRUE;
+ sshc->state = SSH_SESSION_FREE; /* current */
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ break;
+
+ case SSH_QUIT:
+ /* fallthrough, just stop! */
+ default:
+ /* internal error */
+ sshc->nextstate = SSH_NO_STATE;
+ state(conn, SSH_STOP);
+ break;
+ }
+
+ } while(!rc && (sshc->state != SSH_STOP));
+
+ if(rc == LIBSSH2_ERROR_EAGAIN) {
+ /* we would block, we need to wait for the socket to be ready (in the
+ right direction too)! */
+ *block = TRUE;
+ }
+
+ return result;
+}
+
+/* called by the multi interface to figure out what socket(s) to wait for and
+ for what actions in the DO_DONE, PERFORM and WAITPERFORM states */
+static int ssh_perform_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks
+ number of sockets */
+ int numsocks)
+{
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ int bitmap = GETSOCK_BLANK;
+ (void)numsocks;
+
+ sock[0] = conn->sock[FIRSTSOCKET];
+
+ if(conn->waitfor & KEEP_RECV)
+ bitmap |= GETSOCK_READSOCK(FIRSTSOCKET);
+
+ if(conn->waitfor & KEEP_SEND)
+ bitmap |= GETSOCK_WRITESOCK(FIRSTSOCKET);
+
+ return bitmap;
+#else
+ /* if we don't know the direction we can use the generic *_getsock()
+ function even for the protocol_connect and doing states */
+ return Curl_single_getsock(conn, sock, numsocks);
+#endif
+}
+
+/* Generic function called by the multi interface to figure out what socket(s)
+ to wait for and for what actions during the DOING and PROTOCONNECT states*/
+static int ssh_getsock(struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+#ifndef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ (void)conn;
+ (void)sock;
+ (void)numsocks;
+ /* if we don't know any direction we can just play along as we used to and
+ not provide any sensible info */
+ return GETSOCK_BLANK;
+#else
+ /* if we know the direction we can use the generic *_getsock() function even
+ for the protocol_connect and doing states */
+ return ssh_perform_getsock(conn, sock, numsocks);
+#endif
+}
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+/*
+ * When one of the libssh2 functions has returned LIBSSH2_ERROR_EAGAIN this
+ * function is used to figure out in what direction and stores this info so
+ * that the multi interface can take advantage of it. Make sure to call this
+ * function in all cases so that when it _doesn't_ return EAGAIN we can
+ * restore the default wait bits.
+ */
+static void ssh_block2waitfor(struct connectdata *conn, bool block)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ int dir;
+ if(block && (dir = libssh2_session_block_directions(sshc->ssh_session))) {
+ /* translate the libssh2 define bits into our own bit defines */
+ conn->waitfor = ((dir&LIBSSH2_SESSION_BLOCK_INBOUND)?KEEP_RECV:0) |
+ ((dir&LIBSSH2_SESSION_BLOCK_OUTBOUND)?KEEP_SEND:0);
+ }
+ else
+ /* It didn't block or libssh2 didn't reveal in which direction, put back
+ the original set */
+ conn->waitfor = sshc->orig_waitfor;
+}
+#else
+ /* no libssh2 directional support so we simply don't know */
+#define ssh_block2waitfor(x,y) Curl_nop_stmt
+#endif
+
+/* called repeatedly until done from multi.c */
+static CURLcode ssh_multi_statemach(struct connectdata *conn, bool *done)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ CURLcode result = CURLE_OK;
+ bool block; /* we store the status and use that to provide a ssh_getsock()
+ implementation */
+
+ result = ssh_statemach_act(conn, &block);
+ *done = (sshc->state == SSH_STOP) ? TRUE : FALSE;
+ ssh_block2waitfor(conn, block);
+
+ return result;
+}
+
+static CURLcode ssh_block_statemach(struct connectdata *conn,
+ bool duringconnect)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ while((sshc->state != SSH_STOP) && !result) {
+ bool block;
+ long left;
+
+ result = ssh_statemach_act(conn, &block);
+ if(result)
+ break;
+
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ else {
+ struct timeval now = Curl_tvnow();
+ result = Curl_speedcheck(data, now);
+ if(result)
+ break;
+ }
+
+ left = Curl_timeleft(data, NULL, duringconnect);
+ if(left < 0) {
+ failf(data, "Operation timed out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+#ifdef HAVE_LIBSSH2_SESSION_BLOCK_DIRECTION
+ if((CURLE_OK == result) && block) {
+ int dir = libssh2_session_block_directions(sshc->ssh_session);
+ curl_socket_t sock = conn->sock[FIRSTSOCKET];
+ curl_socket_t fd_read = CURL_SOCKET_BAD;
+ curl_socket_t fd_write = CURL_SOCKET_BAD;
+ if(LIBSSH2_SESSION_BLOCK_INBOUND & dir)
+ fd_read = sock;
+ if(LIBSSH2_SESSION_BLOCK_OUTBOUND & dir)
+ fd_write = sock;
+ /* wait for the socket to become ready */
+ Curl_socket_ready(fd_read, fd_write,
+ left>1000?1000:left); /* ignore result */
+ }
+#endif
+
+ }
+
+ return result;
+}
+
+/*
+ * SSH setup and connection
+ */
+static CURLcode ssh_setup_connection(struct connectdata *conn)
+{
+ struct SSHPROTO *ssh;
+
+ conn->data->req.protop = ssh = calloc(1, sizeof(struct SSHPROTO));
+ if(!ssh)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+static Curl_recv scp_recv, sftp_recv;
+static Curl_send scp_send, sftp_send;
+
+/*
+ * Curl_ssh_connect() gets called from Curl_protocol_connect() to allow us to
+ * do protocol-specific actions at connect-time.
+ */
+static CURLcode ssh_connect(struct connectdata *conn, bool *done)
+{
+#ifdef CURL_LIBSSH2_DEBUG
+ curl_socket_t sock;
+#endif
+ struct ssh_conn *ssh;
+ CURLcode result;
+ struct SessionHandle *data = conn->data;
+
+ /* We default to persistent connections. We set this already in this connect
+ function to make the re-use checks properly be able to check this bit. */
+ conn->bits.close = FALSE;
+
+ if(conn->handler->protocol & CURLPROTO_SCP) {
+ conn->recv[FIRSTSOCKET] = scp_recv;
+ conn->send[FIRSTSOCKET] = scp_send;
+ }
+ else {
+ conn->recv[FIRSTSOCKET] = sftp_recv;
+ conn->send[FIRSTSOCKET] = sftp_send;
+ }
+ ssh = &conn->proto.sshc;
+
+#ifdef CURL_LIBSSH2_DEBUG
+ if(conn->user) {
+ infof(data, "User: %s\n", conn->user);
+ }
+ if(conn->passwd) {
+ infof(data, "Password: %s\n", conn->passwd);
+ }
+ sock = conn->sock[FIRSTSOCKET];
+#endif /* CURL_LIBSSH2_DEBUG */
+
+ ssh->ssh_session = libssh2_session_init_ex(my_libssh2_malloc,
+ my_libssh2_free,
+ my_libssh2_realloc, conn);
+ if(ssh->ssh_session == NULL) {
+ failf(data, "Failure initialising ssh session");
+ return CURLE_FAILED_INIT;
+ }
+
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ if(data->set.str[STRING_SSH_KNOWNHOSTS]) {
+ int rc;
+ ssh->kh = libssh2_knownhost_init(ssh->ssh_session);
+ if(!ssh->kh) {
+ /* eeek. TODO: free the ssh_session! */
+ return CURLE_FAILED_INIT;
+ }
+
+ /* read all known hosts from there */
+ rc = libssh2_knownhost_readfile(ssh->kh,
+ data->set.str[STRING_SSH_KNOWNHOSTS],
+ LIBSSH2_KNOWNHOST_FILE_OPENSSH);
+ if(rc < 0)
+ infof(data, "Failed to read known hosts from %s\n",
+ data->set.str[STRING_SSH_KNOWNHOSTS]);
+ }
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#ifdef CURL_LIBSSH2_DEBUG
+ libssh2_trace(ssh->ssh_session, ~0);
+ infof(data, "SSH socket: %d\n", (int)sock);
+#endif /* CURL_LIBSSH2_DEBUG */
+
+ state(conn, SSH_INIT);
+
+ result = ssh_multi_statemach(conn, done);
+
+ return result;
+}
+
+/*
+ ***********************************************************************
+ *
+ * scp_perform()
+ *
+ * This is the actual DO function for SCP. Get a file according to
+ * the options previously setup.
+ */
+
+static
+CURLcode scp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ state(conn, SSH_SCP_TRANS_INIT);
+
+ /* run the state-machine */
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode scp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result;
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ return result;
+}
+
+/*
+ * The DO function is generic for both protocols. There was previously two
+ * separate ones but this way means less duplicated code.
+ */
+
+static CURLcode ssh_do(struct connectdata *conn, bool *done)
+{
+ CURLcode res;
+ bool connected = 0;
+ struct SessionHandle *data = conn->data;
+ struct ssh_conn *sshc = &conn->proto.sshc;
+
+ *done = FALSE; /* default to false */
+
+ data->req.size = -1; /* make sure this is unknown at this point */
+
+ sshc->actualcode = CURLE_OK; /* reset error code */
+ sshc->secondCreateDirs =0; /* reset the create dir attempt state
+ variable */
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+ Curl_pgrsSetUploadSize(data, 0);
+ Curl_pgrsSetDownloadSize(data, 0);
+
+ if(conn->handler->protocol & CURLPROTO_SCP)
+ res = scp_perform(conn, &connected, done);
+ else
+ res = sftp_perform(conn, &connected, done);
+
+ return res;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+ this is still blocking is that the multi interface code has no support for
+ disconnecting operations that takes a while */
+static CURLcode scp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ CURLcode result = CURLE_OK;
+ struct ssh_conn *ssh = &conn->proto.sshc;
+ (void) dead_connection;
+
+ Curl_safefree(conn->data->req.protop);
+
+ if(ssh->ssh_session) {
+ /* only if there's a session still around to use! */
+
+ state(conn, SSH_SESSION_DISCONNECT);
+
+ result = ssh_block_statemach(conn, FALSE);
+ }
+
+ return result;
+}
+
+/* generic done function for both SCP and SFTP called from their specific
+ done functions */
+static CURLcode ssh_done(struct connectdata *conn, CURLcode status)
+{
+ CURLcode result = CURLE_OK;
+ struct SSHPROTO *sftp_scp = conn->data->req.protop;
+
+ if(status == CURLE_OK) {
+ /* run the state-machine
+
+ TODO: when the multi interface is used, this _really_ should be using
+ the ssh_multi_statemach function but we have no general support for
+ non-blocking DONE operations, not in the multi state machine and with
+ Curl_done() invokes on several places in the code!
+ */
+ result = ssh_block_statemach(conn, FALSE);
+ }
+ else
+ result = status;
+
+ if(sftp_scp)
+ Curl_safefree(sftp_scp->path);
+ if(Curl_pgrsDone(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ conn->data->req.keepon = 0; /* clear all bits */
+ return result;
+}
+
+
+static CURLcode scp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ (void)premature; /* not used */
+
+ if(status == CURLE_OK)
+ state(conn, SSH_SCP_DONE);
+
+ return ssh_done(conn, status);
+
+}
+
+/* return number of received (decrypted) bytes */
+static ssize_t scp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ ssize_t nwrite;
+ (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+ /* libssh2_channel_write() returns int! */
+ nwrite = (ssize_t)
+ libssh2_channel_write(conn->proto.sshc.ssh_channel, mem, len);
+
+ ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
+ else if(nwrite < LIBSSH2_ERROR_NONE) {
+ *err = libssh2_session_error_to_CURLE((int)nwrite);
+ nwrite = -1;
+ }
+
+ return nwrite;
+}
+
+/*
+ * If the read would block (EWOULDBLOCK) we return -1. Otherwise we return
+ * a regular CURLcode value.
+ */
+static ssize_t scp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ ssize_t nread;
+ (void)sockindex; /* we only support SCP on the fixed known primary socket */
+
+ /* libssh2_channel_read() returns int */
+ nread = (ssize_t)
+ libssh2_channel_read(conn->proto.sshc.ssh_channel, mem, len);
+
+ ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+ if(nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
+
+ return nread;
+}
+
+/*
+ * =============== SFTP ===============
+ */
+
+/*
+ ***********************************************************************
+ *
+ * sftp_perform()
+ *
+ * This is the actual DO function for SFTP. Get a file/directory according to
+ * the options previously setup.
+ */
+
+static
+CURLcode sftp_perform(struct connectdata *conn,
+ bool *connected,
+ bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+
+ DEBUGF(infof(conn->data, "DO phase starts\n"));
+
+ *dophase_done = FALSE; /* not done yet */
+
+ /* start the first command in the DO phase */
+ state(conn, SSH_SFTP_QUOTE_INIT);
+
+ /* run the state-machine */
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ *connected = conn->bits.tcpconnect[FIRSTSOCKET];
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+
+ return result;
+}
+
+/* called from multi.c while DOing */
+static CURLcode sftp_doing(struct connectdata *conn,
+ bool *dophase_done)
+{
+ CURLcode result;
+ result = ssh_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ return result;
+}
+
+/* BLOCKING, but the function is using the state machine so the only reason
+ this is still blocking is that the multi interface code has no support for
+ disconnecting operations that takes a while */
+static CURLcode sftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ CURLcode result = CURLE_OK;
+ (void) dead_connection;
+
+ DEBUGF(infof(conn->data, "SSH DISCONNECT starts now\n"));
+
+ Curl_safefree(conn->data->req.protop);
+
+ if(conn->proto.sshc.ssh_session) {
+ /* only if there's a session still around to use! */
+ state(conn, SSH_SFTP_SHUTDOWN);
+ result = ssh_block_statemach(conn, FALSE);
+ }
+
+ DEBUGF(infof(conn->data, "SSH DISCONNECT is done\n"));
+
+ return result;
+
+}
+
+static CURLcode sftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ struct ssh_conn *sshc = &conn->proto.sshc;
+
+ if(status == CURLE_OK) {
+ /* Post quote commands are executed after the SFTP_CLOSE state to avoid
+ errors that could happen due to open file handles during POSTQUOTE
+ operation */
+ if(!status && !premature && conn->data->set.postquote) {
+ sshc->nextstate = SSH_SFTP_POSTQUOTE_INIT;
+ state(conn, SSH_SFTP_CLOSE);
+ }
+ else
+ state(conn, SSH_SFTP_CLOSE);
+ }
+ return ssh_done(conn, status);
+}
+
+/* return number of sent bytes */
+static ssize_t sftp_send(struct connectdata *conn, int sockindex,
+ const void *mem, size_t len, CURLcode *err)
+{
+ ssize_t nwrite; /* libssh2_sftp_write() used to return size_t in 0.14
+ but is changed to ssize_t in 0.15. These days we don't
+ support libssh2 0.15*/
+ (void)sockindex;
+
+ nwrite = libssh2_sftp_write(conn->proto.sshc.sftp_handle, mem, len);
+
+ ssh_block2waitfor(conn, (nwrite == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nwrite == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nwrite = 0;
+ }
+ else if(nwrite < LIBSSH2_ERROR_NONE) {
+ *err = libssh2_session_error_to_CURLE((int)nwrite);
+ nwrite = -1;
+ }
+
+ return nwrite;
+}
+
+/*
+ * Return number of received (decrypted) bytes
+ */
+static ssize_t sftp_recv(struct connectdata *conn, int sockindex,
+ char *mem, size_t len, CURLcode *err)
+{
+ ssize_t nread;
+ (void)sockindex;
+
+ nread = libssh2_sftp_read(conn->proto.sshc.sftp_handle, mem, len);
+
+ ssh_block2waitfor(conn, (nread == LIBSSH2_ERROR_EAGAIN)?TRUE:FALSE);
+
+ if(nread == LIBSSH2_ERROR_EAGAIN) {
+ *err = CURLE_AGAIN;
+ nread = -1;
+ }
+ return nread;
+}
+
+/* The get_pathname() function is being borrowed from OpenSSH sftp.c
+ version 4.6p1. */
+/*
+ * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+static CURLcode
+get_pathname(const char **cpp, char **path)
+{
+ const char *cp = *cpp, *end;
+ char quot;
+ unsigned int i, j;
+ static const char WHITESPACE[] = " \t\r\n";
+
+ cp += strspn(cp, WHITESPACE);
+ if(!*cp) {
+ *cpp = cp;
+ *path = NULL;
+ return CURLE_QUOTE_ERROR;
+ }
+
+ *path = malloc(strlen(cp) + 1);
+ if(*path == NULL)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* Check for quoted filenames */
+ if(*cp == '\"' || *cp == '\'') {
+ quot = *cp++;
+
+ /* Search for terminating quote, unescape some chars */
+ for(i = j = 0; i <= strlen(cp); i++) {
+ if(cp[i] == quot) { /* Found quote */
+ i++;
+ (*path)[j] = '\0';
+ break;
+ }
+ if(cp[i] == '\0') { /* End of string */
+ /*error("Unterminated quote");*/
+ goto fail;
+ }
+ if(cp[i] == '\\') { /* Escaped characters */
+ i++;
+ if(cp[i] != '\'' && cp[i] != '\"' &&
+ cp[i] != '\\') {
+ /*error("Bad escaped character '\\%c'",
+ cp[i]);*/
+ goto fail;
+ }
+ }
+ (*path)[j++] = cp[i];
+ }
+
+ if(j == 0) {
+ /*error("Empty quotes");*/
+ goto fail;
+ }
+ *cpp = cp + i + strspn(cp + i, WHITESPACE);
+ }
+ else {
+ /* Read to end of filename */
+ end = strpbrk(cp, WHITESPACE);
+ if(end == NULL)
+ end = strchr(cp, '\0');
+ *cpp = end + strspn(end, WHITESPACE);
+
+ memcpy(*path, cp, end - cp);
+ (*path)[end - cp] = '\0';
+ }
+ return CURLE_OK;
+
+ fail:
+ Curl_safefree(*path);
+ return CURLE_QUOTE_ERROR;
+}
+
+
+static const char *sftp_libssh2_strerror(int err)
+{
+ switch (err) {
+ case LIBSSH2_FX_NO_SUCH_FILE:
+ return "No such file or directory";
+
+ case LIBSSH2_FX_PERMISSION_DENIED:
+ return "Permission denied";
+
+ case LIBSSH2_FX_FAILURE:
+ return "Operation failed";
+
+ case LIBSSH2_FX_BAD_MESSAGE:
+ return "Bad message from SFTP server";
+
+ case LIBSSH2_FX_NO_CONNECTION:
+ return "Not connected to SFTP server";
+
+ case LIBSSH2_FX_CONNECTION_LOST:
+ return "Connection to SFTP server lost";
+
+ case LIBSSH2_FX_OP_UNSUPPORTED:
+ return "Operation not supported by SFTP server";
+
+ case LIBSSH2_FX_INVALID_HANDLE:
+ return "Invalid handle";
+
+ case LIBSSH2_FX_NO_SUCH_PATH:
+ return "No such file or directory";
+
+ case LIBSSH2_FX_FILE_ALREADY_EXISTS:
+ return "File already exists";
+
+ case LIBSSH2_FX_WRITE_PROTECT:
+ return "File is write protected";
+
+ case LIBSSH2_FX_NO_MEDIA:
+ return "No media";
+
+ case LIBSSH2_FX_NO_SPACE_ON_FILESYSTEM:
+ return "Disk full";
+
+ case LIBSSH2_FX_QUOTA_EXCEEDED:
+ return "User quota exceeded";
+
+ case LIBSSH2_FX_UNKNOWN_PRINCIPLE:
+ return "Unknown principle";
+
+ case LIBSSH2_FX_LOCK_CONFlICT:
+ return "File lock conflict";
+
+ case LIBSSH2_FX_DIR_NOT_EMPTY:
+ return "Directory not empty";
+
+ case LIBSSH2_FX_NOT_A_DIRECTORY:
+ return "Not a directory";
+
+ case LIBSSH2_FX_INVALID_FILENAME:
+ return "Invalid filename";
+
+ case LIBSSH2_FX_LINK_LOOP:
+ return "Link points to itself";
+ }
+ return "Unknown error in libssh2";
+}
+
+#endif /* USE_LIBSSH2 */
diff --git a/libs/libcurl/src/ssh.h b/libs/libcurl/src/ssh.h
new file mode 100644
index 0000000000..ff2e16be94
--- /dev/null
+++ b/libs/libcurl/src/ssh.h
@@ -0,0 +1,183 @@
+#ifndef HEADER_CURL_SSH_H
+#define HEADER_CURL_SSH_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/****************************************************************************
+ * SSH unique setup
+ ***************************************************************************/
+typedef enum {
+ SSH_NO_STATE = -1, /* Used for "nextState" so say there is none */
+ SSH_STOP = 0, /* do nothing state, stops the state machine */
+
+ SSH_INIT, /* First state in SSH-CONNECT */
+ SSH_S_STARTUP, /* Session startup */
+ SSH_HOSTKEY, /* verify hostkey */
+ SSH_AUTHLIST,
+ SSH_AUTH_PKEY_INIT,
+ SSH_AUTH_PKEY,
+ SSH_AUTH_PASS_INIT,
+ SSH_AUTH_PASS,
+ SSH_AUTH_AGENT_INIT,/* initialize then wait for connection to agent */
+ SSH_AUTH_AGENT_LIST,/* ask for list then wait for entire list to come */
+ SSH_AUTH_AGENT, /* attempt one key at a time */
+ SSH_AUTH_HOST_INIT,
+ SSH_AUTH_HOST,
+ SSH_AUTH_KEY_INIT,
+ SSH_AUTH_KEY,
+ SSH_AUTH_DONE,
+ SSH_SFTP_INIT,
+ SSH_SFTP_REALPATH, /* Last state in SSH-CONNECT */
+
+ SSH_SFTP_QUOTE_INIT, /* First state in SFTP-DO */
+ SSH_SFTP_POSTQUOTE_INIT, /* (Possibly) First state in SFTP-DONE */
+ SSH_SFTP_QUOTE,
+ SSH_SFTP_NEXT_QUOTE,
+ SSH_SFTP_QUOTE_STAT,
+ SSH_SFTP_QUOTE_SETSTAT,
+ SSH_SFTP_QUOTE_SYMLINK,
+ SSH_SFTP_QUOTE_MKDIR,
+ SSH_SFTP_QUOTE_RENAME,
+ SSH_SFTP_QUOTE_RMDIR,
+ SSH_SFTP_QUOTE_UNLINK,
+ SSH_SFTP_TRANS_INIT,
+ SSH_SFTP_UPLOAD_INIT,
+ SSH_SFTP_CREATE_DIRS_INIT,
+ SSH_SFTP_CREATE_DIRS,
+ SSH_SFTP_CREATE_DIRS_MKDIR,
+ SSH_SFTP_READDIR_INIT,
+ SSH_SFTP_READDIR,
+ SSH_SFTP_READDIR_LINK,
+ SSH_SFTP_READDIR_BOTTOM,
+ SSH_SFTP_READDIR_DONE,
+ SSH_SFTP_DOWNLOAD_INIT,
+ SSH_SFTP_DOWNLOAD_STAT, /* Last state in SFTP-DO */
+ SSH_SFTP_CLOSE, /* Last state in SFTP-DONE */
+ SSH_SFTP_SHUTDOWN, /* First state in SFTP-DISCONNECT */
+ SSH_SCP_TRANS_INIT, /* First state in SCP-DO */
+ SSH_SCP_UPLOAD_INIT,
+ SSH_SCP_DOWNLOAD_INIT,
+ SSH_SCP_DONE,
+ SSH_SCP_SEND_EOF,
+ SSH_SCP_WAIT_EOF,
+ SSH_SCP_WAIT_CLOSE,
+ SSH_SCP_CHANNEL_FREE, /* Last state in SCP-DONE */
+ SSH_SESSION_DISCONNECT, /* First state in SCP-DISCONNECT */
+ SSH_SESSION_FREE, /* Last state in SCP/SFTP-DISCONNECT */
+ SSH_QUIT,
+ SSH_LAST /* never used */
+} sshstate;
+
+/* this struct is used in the HandleData struct which is part of the
+ SessionHandle, which means this is used on a per-easy handle basis.
+ Everything that is strictly related to a connection is banned from this
+ struct. */
+struct SSHPROTO {
+ char *path; /* the path we operate on */
+};
+
+/* ssh_conn is used for struct connection-oriented data in the connectdata
+ struct */
+struct ssh_conn {
+ const char *authlist; /* List of auth. methods, managed by libssh2 */
+#ifdef USE_LIBSSH2
+ const char *passphrase; /* pass-phrase to use */
+ char *rsa_pub; /* path name */
+ char *rsa; /* path name */
+ bool authed; /* the connection has been authenticated fine */
+ sshstate state; /* always use ssh.c:state() to change state! */
+ sshstate nextstate; /* the state to goto after stopping */
+ CURLcode actualcode; /* the actual error code */
+ struct curl_slist *quote_item; /* for the quote option */
+ char *quote_path1; /* two generic pointers for the QUOTE stuff */
+ char *quote_path2;
+ LIBSSH2_SFTP_ATTRIBUTES quote_attrs; /* used by the SFTP_QUOTE state */
+ bool acceptfail; /* used by the SFTP_QUOTE (continue if
+ quote command fails) */
+ char *homedir; /* when doing SFTP we figure out home dir in the
+ connect phase */
+
+ /* Here's a set of struct members used by the SFTP_READDIR state */
+ LIBSSH2_SFTP_ATTRIBUTES readdir_attrs;
+ char *readdir_filename;
+ char *readdir_longentry;
+ int readdir_len, readdir_totalLen, readdir_currLen;
+ char *readdir_line;
+ char *readdir_linkPath;
+ /* end of READDIR stuff */
+
+ int secondCreateDirs; /* counter use by the code to see if the
+ second attempt has been made to change
+ to/create a directory */
+ char *slash_pos; /* used by the SFTP_CREATE_DIRS state */
+ LIBSSH2_SESSION *ssh_session; /* Secure Shell session */
+ LIBSSH2_CHANNEL *ssh_channel; /* Secure Shell channel handle */
+ LIBSSH2_SFTP *sftp_session; /* SFTP handle */
+ LIBSSH2_SFTP_HANDLE *sftp_handle;
+ int orig_waitfor; /* default READ/WRITE bits wait for */
+
+#ifdef HAVE_LIBSSH2_AGENT_API
+ LIBSSH2_AGENT *ssh_agent; /* proxy to ssh-agent/pageant */
+ struct libssh2_agent_publickey *sshagent_identity,
+ *sshagent_prev_identity;
+#endif
+
+ /* note that HAVE_LIBSSH2_KNOWNHOST_API is a define set in the libssh2.h
+ header */
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ LIBSSH2_KNOWNHOSTS *kh;
+#endif
+#endif /* USE_LIBSSH2 */
+};
+
+#ifdef USE_LIBSSH2
+
+#if !defined(LIBSSH2_VERSION_NUM) || (LIBSSH2_VERSION_NUM < 0x001000)
+# error "SCP/SFTP protocols require libssh2 0.16 or later"
+#endif
+
+#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010000)
+# define HAVE_LIBSSH2_SFTP_SEEK64 1
+#else
+# undef HAVE_LIBSSH2_SFTP_SEEK64
+#endif
+
+#if defined(LIBSSH2_VERSION_NUM) && (LIBSSH2_VERSION_NUM >= 0x010206)
+# define HAVE_LIBSSH2_SCP_SEND64 1
+#else
+# undef HAVE_LIBSSH2_SCP_SEND64
+#endif
+
+
+extern const struct Curl_handler Curl_handler_scp;
+extern const struct Curl_handler Curl_handler_sftp;
+
+#endif /* USE_LIBSSH2 */
+
+#endif /* HEADER_CURL_SSH_H */
diff --git a/libs/libcurl/src/sslgen.c b/libs/libcurl/src/sslgen.c
new file mode 100644
index 0000000000..d2d0e303ec
--- /dev/null
+++ b/libs/libcurl/src/sslgen.c
@@ -0,0 +1,676 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/* This file is for implementing all "generic" SSL functions that all libcurl
+ internals should use. It is then responsible for calling the proper
+ "backend" function.
+
+ SSL-functions in libcurl should call functions in this source file, and not
+ to any specific SSL-layer.
+
+ Curl_ssl_ - prefix for generic ones
+ Curl_ossl_ - prefix for OpenSSL ones
+ Curl_gtls_ - prefix for GnuTLS ones
+ Curl_nss_ - prefix for NSS ones
+ Curl_qssl_ - prefix for QsoSSL ones
+ Curl_gskit_ - prefix for GSKit ones
+ Curl_polarssl_ - prefix for PolarSSL ones
+ Curl_cyassl_ - prefix for CyaSSL ones
+ Curl_schannel_ - prefix for Schannel SSPI ones
+ Curl_darwinssl_ - prefix for SecureTransport (Darwin) ones
+
+ Note that this source code uses curlssl_* functions, and they are all
+ defines/macros #defined by the lib-specific header files.
+
+ "SSL/TLS Strong Encryption: An Introduction"
+ http://httpd.apache.org/docs-2.0/ssl/ssl_intro.html
+*/
+
+#include "curl_setup.h"
+
+#ifdef HAVE_SYS_TYPES_H
+#include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+#include <sys/stat.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#include <fcntl.h>
+#endif
+
+#include "urldata.h"
+#define SSLGEN_C
+#include "sslgen.h" /* generic SSL protos etc */
+#include "ssluse.h" /* OpenSSL versions */
+#include "gtls.h" /* GnuTLS versions */
+#include "nssg.h" /* NSS versions */
+#include "qssl.h" /* QSOSSL versions */
+#include "gskit.h" /* Global Secure ToolKit versions */
+#include "polarssl.h" /* PolarSSL versions */
+#include "axtls.h" /* axTLS versions */
+#include "cyassl.h" /* CyaSSL versions */
+#include "curl_schannel.h" /* Schannel SSPI version */
+#include "curl_darwinssl.h" /* SecureTransport (Darwin) version */
+#include "slist.h"
+#include "sendf.h"
+#include "rawstr.h"
+#include "url.h"
+#include "curl_memory.h"
+#include "progress.h"
+#include "share.h"
+#include "timeval.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* convenience macro to check if this handle is using a shared SSL session */
+#define SSLSESSION_SHARED(data) (data->share && \
+ (data->share->specifier & \
+ (1<<CURL_LOCK_DATA_SSL_SESSION)))
+
+static bool safe_strequal(char* str1, char* str2)
+{
+ if(str1 && str2)
+ /* both pointers point to something then compare them */
+ return (0 != Curl_raw_equal(str1, str2)) ? TRUE : FALSE;
+ else
+ /* if both pointers are NULL then treat them as equal */
+ return (!str1 && !str2) ? TRUE : FALSE;
+}
+
+bool
+Curl_ssl_config_matches(struct ssl_config_data* data,
+ struct ssl_config_data* needle)
+{
+ if((data->version == needle->version) &&
+ (data->verifypeer == needle->verifypeer) &&
+ (data->verifyhost == needle->verifyhost) &&
+ safe_strequal(data->CApath, needle->CApath) &&
+ safe_strequal(data->CAfile, needle->CAfile) &&
+ safe_strequal(data->random_file, needle->random_file) &&
+ safe_strequal(data->egdsocket, needle->egdsocket) &&
+ safe_strequal(data->cipher_list, needle->cipher_list))
+ return TRUE;
+
+ return FALSE;
+}
+
+bool
+Curl_clone_ssl_config(struct ssl_config_data *source,
+ struct ssl_config_data *dest)
+{
+ dest->sessionid = source->sessionid;
+ dest->verifyhost = source->verifyhost;
+ dest->verifypeer = source->verifypeer;
+ dest->version = source->version;
+
+ if(source->CAfile) {
+ dest->CAfile = strdup(source->CAfile);
+ if(!dest->CAfile)
+ return FALSE;
+ }
+ else
+ dest->CAfile = NULL;
+
+ if(source->CApath) {
+ dest->CApath = strdup(source->CApath);
+ if(!dest->CApath)
+ return FALSE;
+ }
+ else
+ dest->CApath = NULL;
+
+ if(source->cipher_list) {
+ dest->cipher_list = strdup(source->cipher_list);
+ if(!dest->cipher_list)
+ return FALSE;
+ }
+ else
+ dest->cipher_list = NULL;
+
+ if(source->egdsocket) {
+ dest->egdsocket = strdup(source->egdsocket);
+ if(!dest->egdsocket)
+ return FALSE;
+ }
+ else
+ dest->egdsocket = NULL;
+
+ if(source->random_file) {
+ dest->random_file = strdup(source->random_file);
+ if(!dest->random_file)
+ return FALSE;
+ }
+ else
+ dest->random_file = NULL;
+
+ return TRUE;
+}
+
+void Curl_free_ssl_config(struct ssl_config_data* sslc)
+{
+ Curl_safefree(sslc->CAfile);
+ Curl_safefree(sslc->CApath);
+ Curl_safefree(sslc->cipher_list);
+ Curl_safefree(sslc->egdsocket);
+ Curl_safefree(sslc->random_file);
+}
+
+
+/*
+ * Curl_rand() returns a random unsigned integer, 32bit.
+ *
+ * This non-SSL function is put here only because this file is the only one
+ * with knowledge of what the underlying SSL libraries provide in terms of
+ * randomizers.
+ *
+ * NOTE: 'data' may be passed in as NULL when coming from external API without
+ * easy handle!
+ *
+ */
+
+unsigned int Curl_rand(struct SessionHandle *data)
+{
+ unsigned int r;
+ static unsigned int randseed;
+ static bool seeded = FALSE;
+
+#ifndef have_curlssl_random
+ (void)data;
+#else
+ if(data) {
+ Curl_ssl_random(data, (unsigned char *)&r, sizeof(r));
+ return r;
+ }
+#endif
+
+#ifdef RANDOM_FILE
+ if(!seeded) {
+ /* if there's a random file to read a seed from, use it */
+ int fd = open(RANDOM_FILE, O_RDONLY);
+ if(fd > -1) {
+ /* read random data into the randseed variable */
+ ssize_t nread = read(fd, &randseed, sizeof(randseed));
+ if(nread == sizeof(randseed))
+ seeded = TRUE;
+ close(fd);
+ }
+ }
+#endif
+
+ if(!seeded) {
+ struct timeval now = curlx_tvnow();
+ randseed += (unsigned int)now.tv_usec + (unsigned int)now.tv_sec;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ randseed = randseed * 1103515245 + 12345;
+ seeded = TRUE;
+ }
+
+ /* Return an unsigned 32-bit pseudo-random number. */
+ r = randseed = randseed * 1103515245 + 12345;
+ return (r << 16) | ((r >> 16) & 0xFFFF);
+}
+
+#ifdef USE_SSL
+
+/* "global" init done? */
+static bool init_ssl=FALSE;
+
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ssl_init(void)
+{
+ /* make sure this is only done once */
+ if(init_ssl)
+ return 1;
+ init_ssl = TRUE; /* never again */
+
+ return curlssl_init();
+}
+
+
+/* Global cleanup */
+void Curl_ssl_cleanup(void)
+{
+ if(init_ssl) {
+ /* only cleanup if we did a previous init */
+ curlssl_cleanup();
+ init_ssl = FALSE;
+ }
+}
+
+CURLcode
+Curl_ssl_connect(struct connectdata *conn, int sockindex)
+{
+ CURLcode res;
+ /* mark this is being ssl-enabled from here on. */
+ conn->ssl[sockindex].use = TRUE;
+ conn->ssl[sockindex].state = ssl_connection_negotiating;
+
+ res = curlssl_connect(conn, sockindex);
+
+ if(!res)
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+
+ return res;
+}
+
+CURLcode
+Curl_ssl_connect_nonblocking(struct connectdata *conn, int sockindex,
+ bool *done)
+{
+ CURLcode res;
+ /* mark this is being ssl requested from here on. */
+ conn->ssl[sockindex].use = TRUE;
+#ifdef curlssl_connect_nonblocking
+ res = curlssl_connect_nonblocking(conn, sockindex, done);
+#else
+ *done = TRUE; /* fallback to BLOCKING */
+ res = curlssl_connect(conn, sockindex);
+#endif /* non-blocking connect support */
+ if(!res && *done)
+ Curl_pgrsTime(conn->data, TIMER_APPCONNECT); /* SSL is connected */
+ return res;
+}
+
+/*
+ * Check if there's a session ID for the given connection in the cache, and if
+ * there's one suitable, it is provided. Returns TRUE when no entry matched.
+ */
+int Curl_ssl_getsessionid(struct connectdata *conn,
+ void **ssl_sessionid,
+ size_t *idsize) /* set 0 if unknown */
+{
+ struct curl_ssl_session *check;
+ struct SessionHandle *data = conn->data;
+ size_t i;
+ long *general_age;
+ bool no_match = TRUE;
+
+ *ssl_sessionid = NULL;
+
+ if(!conn->ssl_config.sessionid)
+ /* session ID re-use is disabled */
+ return TRUE;
+
+ /* Lock if shared */
+ if(SSLSESSION_SHARED(data)) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+ general_age = &data->share->sessionage;
+ }
+ else
+ general_age = &data->state.sessionage;
+
+ for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
+ check = &data->state.session[i];
+ if(!check->sessionid)
+ /* not session ID means blank entry */
+ continue;
+ if(Curl_raw_equal(conn->host.name, check->name) &&
+ (conn->remote_port == check->remote_port) &&
+ Curl_ssl_config_matches(&conn->ssl_config, &check->ssl_config)) {
+ /* yes, we have a session ID! */
+ (*general_age)++; /* increase general age */
+ check->age = *general_age; /* set this as used in this age */
+ *ssl_sessionid = check->sessionid;
+ if(idsize)
+ *idsize = check->idsize;
+ no_match = FALSE;
+ break;
+ }
+ }
+
+ /* Unlock */
+ if(SSLSESSION_SHARED(data))
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+
+ return no_match;
+}
+
+/*
+ * Kill a single session ID entry in the cache.
+ */
+void Curl_ssl_kill_session(struct curl_ssl_session *session)
+{
+ if(session->sessionid) {
+ /* defensive check */
+
+ /* free the ID the SSL-layer specific way */
+ curlssl_session_free(session->sessionid);
+
+ session->sessionid = NULL;
+ session->age = 0; /* fresh */
+
+ Curl_free_ssl_config(&session->ssl_config);
+
+ Curl_safefree(session->name);
+ }
+}
+
+/*
+ * Delete the given session ID from the cache.
+ */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid)
+{
+ size_t i;
+ struct SessionHandle *data=conn->data;
+
+ if(SSLSESSION_SHARED(data))
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+
+ for(i = 0; i < data->set.ssl.max_ssl_sessions; i++) {
+ struct curl_ssl_session *check = &data->state.session[i];
+
+ if(check->sessionid == ssl_sessionid) {
+ Curl_ssl_kill_session(check);
+ break;
+ }
+ }
+
+ if(SSLSESSION_SHARED(data))
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+}
+
+/*
+ * Store session id in the session cache. The ID passed on to this function
+ * must already have been extracted and allocated the proper way for the SSL
+ * layer. Curl_XXXX_session_free() will be called to free/kill the session ID
+ * later on.
+ */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+ void *ssl_sessionid,
+ size_t idsize)
+{
+ size_t i;
+ struct SessionHandle *data=conn->data; /* the mother of all structs */
+ struct curl_ssl_session *store = &data->state.session[0];
+ long oldest_age=data->state.session[0].age; /* zero if unused */
+ char *clone_host;
+ long *general_age;
+
+ /* Even though session ID re-use might be disabled, that only disables USING
+ IT. We still store it here in case the re-using is again enabled for an
+ upcoming transfer */
+
+ clone_host = strdup(conn->host.name);
+ if(!clone_host)
+ return CURLE_OUT_OF_MEMORY; /* bail out */
+
+ /* Now we should add the session ID and the host name to the cache, (remove
+ the oldest if necessary) */
+
+ /* If using shared SSL session, lock! */
+ if(SSLSESSION_SHARED(data)) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SSL_SESSION, CURL_LOCK_ACCESS_SINGLE);
+ general_age = &data->share->sessionage;
+ }
+ else {
+ general_age = &data->state.sessionage;
+ }
+
+ /* find an empty slot for us, or find the oldest */
+ for(i = 1; (i < data->set.ssl.max_ssl_sessions) &&
+ data->state.session[i].sessionid; i++) {
+ if(data->state.session[i].age < oldest_age) {
+ oldest_age = data->state.session[i].age;
+ store = &data->state.session[i];
+ }
+ }
+ if(i == data->set.ssl.max_ssl_sessions)
+ /* cache is full, we must "kill" the oldest entry! */
+ Curl_ssl_kill_session(store);
+ else
+ store = &data->state.session[i]; /* use this slot */
+
+ /* now init the session struct wisely */
+ store->sessionid = ssl_sessionid;
+ store->idsize = idsize;
+ store->age = *general_age; /* set current age */
+ if(store->name)
+ /* free it if there's one already present */
+ free(store->name);
+ store->name = clone_host; /* clone host name */
+ store->remote_port = conn->remote_port; /* port number */
+
+
+ /* Unlock */
+ if(SSLSESSION_SHARED(data))
+ Curl_share_unlock(data, CURL_LOCK_DATA_SSL_SESSION);
+
+ if(!Curl_clone_ssl_config(&conn->ssl_config, &store->ssl_config)) {
+ store->sessionid = NULL; /* let caller free sessionid */
+ free(clone_host);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ return CURLE_OK;
+}
+
+
+void Curl_ssl_close_all(struct SessionHandle *data)
+{
+ size_t i;
+ /* kill the session ID cache if not shared */
+ if(data->state.session && !SSLSESSION_SHARED(data)) {
+ for(i = 0; i < data->set.ssl.max_ssl_sessions; i++)
+ /* the single-killer function handles empty table slots */
+ Curl_ssl_kill_session(&data->state.session[i]);
+
+ /* free the cache data */
+ Curl_safefree(data->state.session);
+ }
+
+ curlssl_close_all(data);
+}
+
+void Curl_ssl_close(struct connectdata *conn, int sockindex)
+{
+ DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+ curlssl_close(conn, sockindex);
+}
+
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex)
+{
+ if(curlssl_shutdown(conn, sockindex))
+ return CURLE_SSL_SHUTDOWN_FAILED;
+
+ conn->ssl[sockindex].use = FALSE; /* get back to ordinary socket usage */
+ conn->ssl[sockindex].state = ssl_connection_none;
+
+ conn->recv[sockindex] = Curl_recv_plain;
+ conn->send[sockindex] = Curl_send_plain;
+
+ return CURLE_OK;
+}
+
+/* Selects an SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine)
+{
+ return curlssl_set_engine(data, engine);
+}
+
+/* Selects the default SSL crypto engine
+ */
+CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data)
+{
+ return curlssl_set_engine_default(data);
+}
+
+/* Return list of OpenSSL crypto engine names. */
+struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data)
+{
+ return curlssl_engines_list(data);
+}
+
+/*
+ * This sets up a session ID cache to the specified size. Make sure this code
+ * is agnostic to what underlying SSL technology we use.
+ */
+CURLcode Curl_ssl_initsessions(struct SessionHandle *data, size_t amount)
+{
+ struct curl_ssl_session *session;
+
+ if(data->state.session)
+ /* this is just a precaution to prevent multiple inits */
+ return CURLE_OK;
+
+ session = calloc(amount, sizeof(struct curl_ssl_session));
+ if(!session)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* store the info in the SSL section */
+ data->set.ssl.max_ssl_sessions = amount;
+ data->state.session = session;
+ data->state.sessionage = 1; /* this is brand new */
+ return CURLE_OK;
+}
+
+size_t Curl_ssl_version(char *buffer, size_t size)
+{
+ return curlssl_version(buffer, size);
+}
+
+/*
+ * This function tries to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_ssl_check_cxn(struct connectdata *conn)
+{
+ return curlssl_check_cxn(conn);
+}
+
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+ int connindex)
+{
+ return curlssl_data_pending(conn, connindex);
+}
+
+void Curl_ssl_free_certinfo(struct SessionHandle *data)
+{
+ int i;
+ struct curl_certinfo *ci = &data->info.certs;
+ if(ci->num_of_certs) {
+ /* free all individual lists used */
+ for(i=0; i<ci->num_of_certs; i++) {
+ curl_slist_free_all(ci->certinfo[i]);
+ ci->certinfo[i] = NULL;
+ }
+ free(ci->certinfo); /* free the actual array too */
+ ci->certinfo = NULL;
+ ci->num_of_certs = 0;
+ }
+}
+
+int Curl_ssl_init_certinfo(struct SessionHandle * data,
+ int num)
+{
+ struct curl_certinfo * ci = &data->info.certs;
+ struct curl_slist * * table;
+
+ /* Initialize the certificate information structures. Return 0 if OK, else 1.
+ */
+ Curl_ssl_free_certinfo(data);
+ ci->num_of_certs = num;
+ table = calloc((size_t) num, sizeof(struct curl_slist *));
+ if(!table)
+ return 1;
+
+ ci->certinfo = table;
+ return 0;
+}
+
+CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle *data,
+ int certnum,
+ const char *label,
+ const char *value,
+ size_t valuelen)
+{
+ struct curl_certinfo * ci = &data->info.certs;
+ char * output;
+ struct curl_slist * nl;
+ CURLcode res = CURLE_OK;
+
+ /* Add an information record for a particular certificate. */
+ output = curl_maprintf("%s:%.*s", label, valuelen, value);
+ if(!output)
+ return CURLE_OUT_OF_MEMORY;
+
+ nl = Curl_slist_append_nodup(ci->certinfo[certnum], output);
+ if(!nl) {
+ free(output);
+ curl_slist_free_all(ci->certinfo[certnum]);
+ res = CURLE_OUT_OF_MEMORY;
+ }
+
+ ci->certinfo[certnum] = nl;
+ return res;
+}
+
+/*
+ * This is a convenience function for push_certinfo_len that takes a zero
+ * terminated value.
+ */
+CURLcode Curl_ssl_push_certinfo(struct SessionHandle *data,
+ int certnum,
+ const char *label,
+ const char *value)
+{
+ size_t valuelen = strlen(value);
+
+ return Curl_ssl_push_certinfo_len(data, certnum, label, value, valuelen);
+}
+
+/* these functions are only provided by some SSL backends */
+
+#ifdef have_curlssl_random
+void Curl_ssl_random(struct SessionHandle *data,
+ unsigned char *entropy,
+ size_t length)
+{
+ curlssl_random(data, entropy, length);
+}
+#endif
+
+#ifdef have_curlssl_md5sum
+void Curl_ssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len)
+{
+ curlssl_md5sum(tmp, tmplen, md5sum, md5len);
+}
+#endif
+
+#endif /* USE_SSL */
diff --git a/libs/libcurl/src/sslgen.h b/libs/libcurl/src/sslgen.h
new file mode 100644
index 0000000000..c7f5f0092d
--- /dev/null
+++ b/libs/libcurl/src/sslgen.h
@@ -0,0 +1,126 @@
+#ifndef HEADER_CURL_SSLGEN_H
+#define HEADER_CURL_SSLGEN_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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"
+
+#ifndef MD5_DIGEST_LENGTH
+#define MD5_DIGEST_LENGTH 16 /* fixed size */
+#endif
+
+bool Curl_ssl_config_matches(struct ssl_config_data* data,
+ struct ssl_config_data* needle);
+bool Curl_clone_ssl_config(struct ssl_config_data* source,
+ struct ssl_config_data* dest);
+void Curl_free_ssl_config(struct ssl_config_data* sslc);
+
+unsigned int Curl_rand(struct SessionHandle *);
+
+#ifdef USE_SSL
+int Curl_ssl_init(void);
+void Curl_ssl_cleanup(void);
+CURLcode Curl_ssl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+/* tell the SSL stuff to close down all open information regarding
+ connections (and thus session ID caching etc) */
+void Curl_ssl_close_all(struct SessionHandle *data);
+void Curl_ssl_close(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_shutdown(struct connectdata *conn, int sockindex);
+CURLcode Curl_ssl_set_engine(struct SessionHandle *data, const char *engine);
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ssl_set_engine_default(struct SessionHandle *data);
+struct curl_slist *Curl_ssl_engines_list(struct SessionHandle *data);
+
+/* init the SSL session ID cache */
+CURLcode Curl_ssl_initsessions(struct SessionHandle *, size_t);
+size_t Curl_ssl_version(char *buffer, size_t size);
+bool Curl_ssl_data_pending(const struct connectdata *conn,
+ int connindex);
+int Curl_ssl_check_cxn(struct connectdata *conn);
+
+/* Certificate information list handling. */
+
+void Curl_ssl_free_certinfo(struct SessionHandle *data);
+int Curl_ssl_init_certinfo(struct SessionHandle * data, int num);
+CURLcode Curl_ssl_push_certinfo_len(struct SessionHandle * data, int certnum,
+ const char * label, const char * value,
+ size_t valuelen);
+CURLcode Curl_ssl_push_certinfo(struct SessionHandle * data, int certnum,
+ const char * label, const char * value);
+
+/* Functions to be used by SSL library adaptation functions */
+
+/* extract a session ID */
+int Curl_ssl_getsessionid(struct connectdata *conn,
+ void **ssl_sessionid,
+ size_t *idsize) /* set 0 if unknown */;
+/* add a new session ID */
+CURLcode Curl_ssl_addsessionid(struct connectdata *conn,
+ void *ssl_sessionid,
+ size_t idsize);
+/* Kill a single session ID entry in the cache */
+void Curl_ssl_kill_session(struct curl_ssl_session *session);
+/* delete a session from the cache */
+void Curl_ssl_delsessionid(struct connectdata *conn, void *ssl_sessionid);
+
+/* get N random bytes into the buffer */
+void Curl_ssl_random(struct SessionHandle *data, unsigned char *buffer,
+ size_t length);
+void Curl_ssl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum, /* output */
+ size_t md5len);
+
+#define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */
+
+#ifdef have_curlssl_random
+#define HAVE_CURL_SSL_RANDOM
+#endif
+#ifdef have_curlssl_md5sum
+#define HAVE_CURL_SSL_MD5SUM
+#endif
+
+#else
+/* When SSL support is not present, just define away these function calls */
+#define Curl_ssl_init() 1
+#define Curl_ssl_cleanup() Curl_nop_stmt
+#define Curl_ssl_connect(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_close_all(x) Curl_nop_stmt
+#define Curl_ssl_close(x,y) Curl_nop_stmt
+#define Curl_ssl_shutdown(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_set_engine(x,y) CURLE_NOT_BUILT_IN
+#define Curl_ssl_set_engine_default(x) CURLE_NOT_BUILT_IN
+#define Curl_ssl_engines_list(x) NULL
+#define Curl_ssl_send(a,b,c,d,e) -1
+#define Curl_ssl_recv(a,b,c,d,e) -1
+#define Curl_ssl_initsessions(x,y) CURLE_OK
+#define Curl_ssl_version(x,y) 0
+#define Curl_ssl_data_pending(x,y) 0
+#define Curl_ssl_check_cxn(x) 0
+#define Curl_ssl_free_certinfo(x) Curl_nop_stmt
+#define Curl_ssl_connect_nonblocking(x,y,z) CURLE_NOT_BUILT_IN
+#define Curl_ssl_kill_session(x) Curl_nop_stmt
+#endif
+
+#endif /* HEADER_CURL_SSLGEN_H */
diff --git a/libs/libcurl/src/ssluse.c b/libs/libcurl/src/ssluse.c
new file mode 100644
index 0000000000..25ece337a1
--- /dev/null
+++ b/libs/libcurl/src/ssluse.c
@@ -0,0 +1,2696 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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.
+ *
+ ***************************************************************************/
+
+/*
+ * Source file for all OpenSSL-specific code for the TLS/SSL layer. No code
+ * but sslgen.c should ever call or use these functions.
+ */
+
+/*
+ * The original SSLeay-using code for curl was written by Linas Vepstas and
+ * Sampo Kellomaki 1998.
+ */
+
+#include "curl_setup.h"
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#include "urldata.h"
+#include "sendf.h"
+#include "formdata.h" /* for the boundary function */
+#include "url.h" /* for the ssl config check function */
+#include "inet_pton.h"
+#include "ssluse.h"
+#include "connect.h"
+#include "slist.h"
+#include "strequal.h"
+#include "select.h"
+#include "sslgen.h"
+#include "rawstr.h"
+#include "hostcheck.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_SSLEAY
+
+#ifdef USE_OPENSSL
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/dsa.h>
+#include <openssl/dh.h>
+#include <openssl/err.h>
+#include <openssl/md5.h>
+#else
+#include <rand.h>
+#include <x509v3.h>
+#include <md5.h>
+#endif
+
+#include "warnless.h"
+#include "curl_memory.h"
+#include "non-ascii.h" /* for Curl_convert_from_utf8 prototype */
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#ifndef OPENSSL_VERSION_NUMBER
+#error "OPENSSL_VERSION_NUMBER not defined"
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x0090581fL
+#define HAVE_SSL_GET1_SESSION 1
+#else
+#undef HAVE_SSL_GET1_SESSION
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00904100L
+#define HAVE_USERDATA_IN_PWD_CALLBACK 1
+#else
+#undef HAVE_USERDATA_IN_PWD_CALLBACK
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907001L
+/* ENGINE_load_private_key() takes four arguments */
+#define HAVE_ENGINE_LOAD_FOUR_ARGS
+#include <openssl/ui.h>
+#else
+/* ENGINE_load_private_key() takes three arguments */
+#undef HAVE_ENGINE_LOAD_FOUR_ARGS
+#endif
+
+#if (OPENSSL_VERSION_NUMBER >= 0x00903001L) && defined(HAVE_OPENSSL_PKCS12_H)
+/* OpenSSL has PKCS 12 support */
+#define HAVE_PKCS12_SUPPORT
+#else
+/* OpenSSL/SSLEay does not have PKCS12 support */
+#undef HAVE_PKCS12_SUPPORT
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00906001L
+#define HAVE_ERR_ERROR_STRING_N 1
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+#define SSL_METHOD_QUAL const
+#else
+#define SSL_METHOD_QUAL
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x00907000L
+/* 0.9.6 didn't have X509_STORE_set_flags() */
+#define HAVE_X509_STORE_SET_FLAGS 1
+#else
+#define X509_STORE_set_flags(x,y) Curl_nop_stmt
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x10000000L
+#define HAVE_ERR_REMOVE_THREAD_STATE 1
+#endif
+
+#ifndef HAVE_SSLV2_CLIENT_METHOD
+#undef OPENSSL_NO_SSL2 /* undef first to avoid compiler warnings */
+#define OPENSSL_NO_SSL2
+#endif
+
+/*
+ * Number of bytes to read from the random number seed file. This must be
+ * a finite value (because some entropy "files" like /dev/urandom have
+ * an infinite length), but must be large enough to provide enough
+ * entopy to properly seed OpenSSL's PRNG.
+ */
+#define RAND_LOAD_LENGTH 1024
+
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+static char global_passwd[64];
+#endif
+
+static int passwd_callback(char *buf, int num, int encrypting
+#ifdef HAVE_USERDATA_IN_PWD_CALLBACK
+ /* This was introduced in 0.9.4, we can set this
+ using SSL_CTX_set_default_passwd_cb_userdata()
+ */
+ , void *global_passwd
+#endif
+ )
+{
+ DEBUGASSERT(0 == encrypting);
+
+ if(!encrypting) {
+ int klen = curlx_uztosi(strlen((char *)global_passwd));
+ if(num > klen) {
+ memcpy(buf, global_passwd, klen+1);
+ return klen;
+ }
+ }
+ return 0;
+}
+
+/*
+ * rand_enough() is a function that returns TRUE if we have seeded the random
+ * engine properly. We use some preprocessor magic to provide a seed_enough()
+ * macro to use, just to prevent a compiler warning on this function if we
+ * pass in an argument that is never used.
+ */
+
+#ifdef HAVE_RAND_STATUS
+#define seed_enough(x) rand_enough()
+static bool rand_enough(void)
+{
+ return (0 != RAND_status()) ? TRUE : FALSE;
+}
+#else
+#define seed_enough(x) rand_enough(x)
+static bool rand_enough(int nread)
+{
+ /* this is a very silly decision to make */
+ return (nread > 500) ? TRUE : FALSE;
+}
+#endif
+
+static int ossl_seed(struct SessionHandle *data)
+{
+ char *buf = data->state.buffer; /* point to the big buffer */
+ int nread=0;
+
+ /* Q: should we add support for a random file name as a libcurl option?
+ A: Yes, it is here */
+
+#ifndef RANDOM_FILE
+ /* if RANDOM_FILE isn't defined, we only perform this if an option tells
+ us to! */
+ if(data->set.ssl.random_file)
+#define RANDOM_FILE "" /* doesn't matter won't be used */
+#endif
+ {
+ /* let the option override the define */
+ nread += RAND_load_file((data->set.str[STRING_SSL_RANDOM_FILE]?
+ data->set.str[STRING_SSL_RANDOM_FILE]:
+ RANDOM_FILE),
+ RAND_LOAD_LENGTH);
+ if(seed_enough(nread))
+ return nread;
+ }
+
+#if defined(HAVE_RAND_EGD)
+ /* only available in OpenSSL 0.9.5 and later */
+ /* EGD_SOCKET is set at configure time or not at all */
+#ifndef EGD_SOCKET
+ /* If we don't have the define set, we only do this if the egd-option
+ is set */
+ if(data->set.str[STRING_SSL_EGDSOCKET])
+#define EGD_SOCKET "" /* doesn't matter won't be used */
+#endif
+ {
+ /* If there's an option and a define, the option overrides the
+ define */
+ int ret = RAND_egd(data->set.str[STRING_SSL_EGDSOCKET]?
+ data->set.str[STRING_SSL_EGDSOCKET]:EGD_SOCKET);
+ if(-1 != ret) {
+ nread += ret;
+ if(seed_enough(nread))
+ return nread;
+ }
+ }
+#endif
+
+ /* If we get here, it means we need to seed the PRNG using a "silly"
+ approach! */
+ do {
+ unsigned char randb[64];
+ int len = sizeof(randb);
+ RAND_bytes(randb, len);
+ RAND_add(randb, len, (len >> 1));
+ } while(!RAND_status());
+
+ /* generates a default path for the random seed file */
+ buf[0]=0; /* blank it first */
+ RAND_file_name(buf, BUFSIZE);
+ if(buf[0]) {
+ /* we got a file name to try */
+ nread += RAND_load_file(buf, RAND_LOAD_LENGTH);
+ if(seed_enough(nread))
+ return nread;
+ }
+
+ infof(data, "libcurl is now using a weak random seed!\n");
+ return nread;
+}
+
+int Curl_ossl_seed(struct SessionHandle *data)
+{
+ /* we have the "SSL is seeded" boolean static to prevent multiple
+ time-consuming seedings in vain */
+ static bool ssl_seeded = FALSE;
+
+ if(!ssl_seeded || data->set.str[STRING_SSL_RANDOM_FILE] ||
+ data->set.str[STRING_SSL_EGDSOCKET]) {
+ ossl_seed(data);
+ ssl_seeded = TRUE;
+ }
+ return 0;
+}
+
+
+#ifndef SSL_FILETYPE_ENGINE
+#define SSL_FILETYPE_ENGINE 42
+#endif
+#ifndef SSL_FILETYPE_PKCS12
+#define SSL_FILETYPE_PKCS12 43
+#endif
+static int do_file_type(const char *type)
+{
+ if(!type || !type[0])
+ return SSL_FILETYPE_PEM;
+ if(Curl_raw_equal(type, "PEM"))
+ return SSL_FILETYPE_PEM;
+ if(Curl_raw_equal(type, "DER"))
+ return SSL_FILETYPE_ASN1;
+ if(Curl_raw_equal(type, "ENG"))
+ return SSL_FILETYPE_ENGINE;
+ if(Curl_raw_equal(type, "P12"))
+ return SSL_FILETYPE_PKCS12;
+ return -1;
+}
+
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(HAVE_ENGINE_LOAD_FOUR_ARGS)
+/*
+ * Supply default password to the engine user interface conversation.
+ * The password is passed by OpenSSL engine from ENGINE_load_private_key()
+ * last argument to the ui and can be obtained by UI_get0_user_data(ui) here.
+ */
+static int ssl_ui_reader(UI *ui, UI_STRING *uis)
+{
+ const char *password;
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT:
+ case UIT_VERIFY:
+ password = (const char*)UI_get0_user_data(ui);
+ if(NULL != password &&
+ UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) {
+ UI_set_result(ui, uis, password);
+ return 1;
+ }
+ default:
+ break;
+ }
+ return (UI_method_get_reader(UI_OpenSSL()))(ui, uis);
+}
+
+/*
+ * Suppress interactive request for a default password if available.
+ */
+static int ssl_ui_writer(UI *ui, UI_STRING *uis)
+{
+ switch(UI_get_string_type(uis)) {
+ case UIT_PROMPT:
+ case UIT_VERIFY:
+ if(NULL != UI_get0_user_data(ui) &&
+ UI_get_input_flags(uis) & UI_INPUT_FLAG_DEFAULT_PWD) {
+ return 1;
+ }
+ default:
+ break;
+ }
+ return (UI_method_get_writer(UI_OpenSSL()))(ui, uis);
+}
+#endif
+
+static
+int cert_stuff(struct connectdata *conn,
+ SSL_CTX* ctx,
+ char *cert_file,
+ const char *cert_type,
+ char *key_file,
+ const char *key_type)
+{
+ struct SessionHandle *data = conn->data;
+
+ int file_type = do_file_type(cert_type);
+
+ if(cert_file != NULL || file_type == SSL_FILETYPE_ENGINE) {
+ SSL *ssl;
+ X509 *x509;
+ int cert_done = 0;
+
+ if(data->set.str[STRING_KEY_PASSWD]) {
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+ /*
+ * If password has been given, we store that in the global
+ * area (*shudder*) for a while:
+ */
+ size_t len = strlen(data->set.str[STRING_KEY_PASSWD]);
+ if(len < sizeof(global_passwd))
+ memcpy(global_passwd, data->set.str[STRING_KEY_PASSWD], len+1);
+ else
+ global_passwd[0] = '\0';
+#else
+ /*
+ * We set the password in the callback userdata
+ */
+ SSL_CTX_set_default_passwd_cb_userdata(ctx,
+ data->set.str[STRING_KEY_PASSWD]);
+#endif
+ /* Set passwd callback: */
+ SSL_CTX_set_default_passwd_cb(ctx, passwd_callback);
+ }
+
+
+#define SSL_CLIENT_CERT_ERR \
+ "unable to use client certificate (no key found or wrong pass phrase?)"
+
+ switch(file_type) {
+ case SSL_FILETYPE_PEM:
+ /* SSL_CTX_use_certificate_chain_file() only works on PEM files */
+ if(SSL_CTX_use_certificate_chain_file(ctx,
+ cert_file) != 1) {
+ failf(data, SSL_CLIENT_CERT_ERR);
+ return 0;
+ }
+ break;
+
+ case SSL_FILETYPE_ASN1:
+ /* SSL_CTX_use_certificate_file() works with either PEM or ASN1, but
+ we use the case above for PEM so this can only be performed with
+ ASN1 files. */
+ if(SSL_CTX_use_certificate_file(ctx,
+ cert_file,
+ file_type) != 1) {
+ failf(data, SSL_CLIENT_CERT_ERR);
+ return 0;
+ }
+ break;
+ case SSL_FILETYPE_ENGINE:
+#if defined(HAVE_OPENSSL_ENGINE_H) && defined(ENGINE_CTRL_GET_CMD_FROM_NAME)
+ {
+ if(data->state.engine) {
+ const char *cmd_name = "LOAD_CERT_CTRL";
+ struct {
+ const char *cert_id;
+ X509 *cert;
+ } params;
+
+ params.cert_id = cert_file;
+ params.cert = NULL;
+
+ /* Does the engine supports LOAD_CERT_CTRL ? */
+ if(!ENGINE_ctrl(data->state.engine, ENGINE_CTRL_GET_CMD_FROM_NAME,
+ 0, (void *)cmd_name, NULL)) {
+ failf(data, "ssl engine does not support loading certificates");
+ return 0;
+ }
+
+ /* Load the certificate from the engine */
+ if(!ENGINE_ctrl_cmd(data->state.engine, cmd_name,
+ 0, &params, NULL, 1)) {
+ failf(data, "ssl engine cannot load client cert with id"
+ " '%s' [%s]", cert_file,
+ ERR_error_string(ERR_get_error(), NULL));
+ return 0;
+ }
+
+ if(!params.cert) {
+ failf(data, "ssl engine didn't initialized the certificate "
+ "properly.");
+ return 0;
+ }
+
+ if(SSL_CTX_use_certificate(ctx, params.cert) != 1) {
+ failf(data, "unable to set client certificate");
+ X509_free(params.cert);
+ return 0;
+ }
+ X509_free(params.cert); /* we don't need the handle any more... */
+ }
+ else {
+ failf(data, "crypto engine not set, can't load certificate");
+ return 0;
+ }
+ }
+ break;
+#else
+ failf(data, "file type ENG for certificate not implemented");
+ return 0;
+#endif
+
+ case SSL_FILETYPE_PKCS12:
+ {
+#ifdef HAVE_PKCS12_SUPPORT
+ FILE *f;
+ PKCS12 *p12;
+ EVP_PKEY *pri;
+ STACK_OF(X509) *ca = NULL;
+ int i;
+
+ f = fopen(cert_file,"rb");
+ if(!f) {
+ failf(data, "could not open PKCS12 file '%s'", cert_file);
+ return 0;
+ }
+ p12 = d2i_PKCS12_fp(f, NULL);
+ fclose(f);
+
+ if(!p12) {
+ failf(data, "error reading PKCS12 file '%s'", cert_file );
+ return 0;
+ }
+
+ PKCS12_PBE_add();
+
+ if(!PKCS12_parse(p12, data->set.str[STRING_KEY_PASSWD], &pri, &x509,
+ &ca)) {
+ failf(data,
+ "could not parse PKCS12 file, check password, OpenSSL error %s",
+ ERR_error_string(ERR_get_error(), NULL) );
+ PKCS12_free(p12);
+ return 0;
+ }
+
+ PKCS12_free(p12);
+
+ if(SSL_CTX_use_certificate(ctx, x509) != 1) {
+ failf(data, SSL_CLIENT_CERT_ERR);
+ goto fail;
+ }
+
+ if(SSL_CTX_use_PrivateKey(ctx, pri) != 1) {
+ failf(data, "unable to use private key from PKCS12 file '%s'",
+ cert_file);
+ goto fail;
+ }
+
+ if(!SSL_CTX_check_private_key (ctx)) {
+ failf(data, "private key from PKCS12 file '%s' "
+ "does not match certificate in same file", cert_file);
+ goto fail;
+ }
+ /* Set Certificate Verification chain */
+ if(ca && sk_X509_num(ca)) {
+ for(i = 0; i < sk_X509_num(ca); i++) {
+ /*
+ * Note that sk_X509_pop() is used below to make sure the cert is
+ * removed from the stack properly before getting passed to
+ * SSL_CTX_add_extra_chain_cert(). Previously we used
+ * sk_X509_value() instead, but then we'd clean it in the subsequent
+ * sk_X509_pop_free() call.
+ */
+ X509 *x = sk_X509_pop(ca);
+ if(!SSL_CTX_add_extra_chain_cert(ctx, x)) {
+ failf(data, "cannot add certificate to certificate chain");
+ goto fail;
+ }
+ /* SSL_CTX_add_client_CA() seems to work with either sk_* function,
+ * presumably because it duplicates what we pass to it.
+ */
+ if(!SSL_CTX_add_client_CA(ctx, x)) {
+ failf(data, "cannot add certificate to client CA list");
+ goto fail;
+ }
+ }
+ }
+
+ cert_done = 1;
+ fail:
+ EVP_PKEY_free(pri);
+ X509_free(x509);
+ sk_X509_pop_free(ca, X509_free);
+
+ if(!cert_done)
+ return 0; /* failure! */
+#else
+ failf(data, "file type P12 for certificate not supported");
+ return 0;
+#endif
+ }
+ default:
+ failf(data, "not supported file type '%s' for certificate", cert_type);
+ return 0;
+ }
+
+ file_type = do_file_type(key_type);
+
+ switch(file_type) {
+ case SSL_FILETYPE_PEM:
+ if(cert_done)
+ break;
+ if(key_file == NULL)
+ /* cert & key can only be in PEM case in the same file */
+ key_file=cert_file;
+ case SSL_FILETYPE_ASN1:
+ if(SSL_CTX_use_PrivateKey_file(ctx, key_file, file_type) != 1) {
+ failf(data, "unable to set private key file: '%s' type %s",
+ key_file, key_type?key_type:"PEM");
+ return 0;
+ }
+ break;
+ case SSL_FILETYPE_ENGINE:
+#ifdef HAVE_OPENSSL_ENGINE_H
+ { /* XXXX still needs some work */
+ EVP_PKEY *priv_key = NULL;
+ if(data->state.engine) {
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+ UI_METHOD *ui_method =
+ UI_create_method((char *)"cURL user interface");
+ if(NULL == ui_method) {
+ failf(data, "unable do create OpenSSL user-interface method");
+ return 0;
+ }
+ UI_method_set_opener(ui_method, UI_method_get_opener(UI_OpenSSL()));
+ UI_method_set_closer(ui_method, UI_method_get_closer(UI_OpenSSL()));
+ UI_method_set_reader(ui_method, ssl_ui_reader);
+ UI_method_set_writer(ui_method, ssl_ui_writer);
+#endif
+ /* the typecast below was added to please mingw32 */
+ priv_key = (EVP_PKEY *)
+ ENGINE_load_private_key(data->state.engine,key_file,
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+ ui_method,
+#endif
+ data->set.str[STRING_KEY_PASSWD]);
+#ifdef HAVE_ENGINE_LOAD_FOUR_ARGS
+ UI_destroy_method(ui_method);
+#endif
+ if(!priv_key) {
+ failf(data, "failed to load private key from crypto engine");
+ return 0;
+ }
+ if(SSL_CTX_use_PrivateKey(ctx, priv_key) != 1) {
+ failf(data, "unable to set private key");
+ EVP_PKEY_free(priv_key);
+ return 0;
+ }
+ EVP_PKEY_free(priv_key); /* we don't need the handle any more... */
+ }
+ else {
+ failf(data, "crypto engine not set, can't load private key");
+ return 0;
+ }
+ }
+ break;
+#else
+ failf(data, "file type ENG for private key not supported");
+ return 0;
+#endif
+ case SSL_FILETYPE_PKCS12:
+ if(!cert_done) {
+ failf(data, "file type P12 for private key not supported");
+ return 0;
+ }
+ break;
+ default:
+ failf(data, "not supported file type for private key");
+ return 0;
+ }
+
+ ssl=SSL_new(ctx);
+ if(NULL == ssl) {
+ failf(data,"unable to create an SSL structure");
+ return 0;
+ }
+
+ x509=SSL_get_certificate(ssl);
+
+ /* This version was provided by Evan Jordan and is supposed to not
+ leak memory as the previous version: */
+ if(x509 != NULL) {
+ EVP_PKEY *pktmp = X509_get_pubkey(x509);
+ EVP_PKEY_copy_parameters(pktmp,SSL_get_privatekey(ssl));
+ EVP_PKEY_free(pktmp);
+ }
+
+ SSL_free(ssl);
+
+ /* If we are using DSA, we can copy the parameters from
+ * the private key */
+
+
+ /* Now we know that a key and cert have been set against
+ * the SSL context */
+ if(!SSL_CTX_check_private_key(ctx)) {
+ failf(data, "Private key does not match the certificate public key");
+ return 0;
+ }
+#ifndef HAVE_USERDATA_IN_PWD_CALLBACK
+ /* erase it now */
+ memset(global_passwd, 0, sizeof(global_passwd));
+#endif
+ }
+ return 1;
+}
+
+/* returns non-zero on failure */
+static int x509_name_oneline(X509_NAME *a, char *buf, size_t size)
+{
+#if 0
+ return X509_NAME_oneline(a, buf, size);
+#else
+ BIO *bio_out = BIO_new(BIO_s_mem());
+ BUF_MEM *biomem;
+ int rc;
+
+ if(!bio_out)
+ return 1; /* alloc failed! */
+
+ rc = X509_NAME_print_ex(bio_out, a, 0, XN_FLAG_SEP_SPLUS_SPC);
+ BIO_get_mem_ptr(bio_out, &biomem);
+
+ if((size_t)biomem->length < size)
+ size = biomem->length;
+ else
+ size--; /* don't overwrite the buffer end */
+
+ memcpy(buf, biomem->data, size);
+ buf[size]=0;
+
+ BIO_free(bio_out);
+
+ return !rc;
+#endif
+}
+
+static
+int cert_verify_callback(int ok, X509_STORE_CTX *ctx)
+{
+ X509 *err_cert;
+ char buf[256];
+
+ err_cert=X509_STORE_CTX_get_current_cert(ctx);
+ (void)x509_name_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf));
+ return ok;
+}
+
+/* Return error string for last OpenSSL error
+ */
+static char *SSL_strerror(unsigned long error, char *buf, size_t size)
+{
+#ifdef HAVE_ERR_ERROR_STRING_N
+ /* OpenSSL 0.9.6 and later has a function named
+ ERRO_error_string_n() that takes the size of the buffer as a
+ third argument */
+ ERR_error_string_n(error, buf, size);
+#else
+ (void) size;
+ ERR_error_string(error, buf);
+#endif
+ return buf;
+}
+
+#endif /* USE_SSLEAY */
+
+#ifdef USE_SSLEAY
+/**
+ * Global SSL init
+ *
+ * @retval 0 error initializing SSL
+ * @retval 1 SSL initialized successfully
+ */
+int Curl_ossl_init(void)
+{
+#ifdef HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+ ENGINE_load_builtin_engines();
+#endif
+
+ /* Lets get nice error messages */
+ SSL_load_error_strings();
+
+ /* Init the global ciphers and digests */
+ if(!SSLeay_add_ssl_algorithms())
+ return 0;
+
+ OpenSSL_add_all_algorithms();
+
+ return 1;
+}
+
+#endif /* USE_SSLEAY */
+
+#ifdef USE_SSLEAY
+
+/* Global cleanup */
+void Curl_ossl_cleanup(void)
+{
+ /* Free ciphers and digests lists */
+ EVP_cleanup();
+
+#ifdef HAVE_ENGINE_CLEANUP
+ /* Free engine list */
+ ENGINE_cleanup();
+#endif
+
+#ifdef HAVE_CRYPTO_CLEANUP_ALL_EX_DATA
+ /* Free OpenSSL ex_data table */
+ CRYPTO_cleanup_all_ex_data();
+#endif
+
+ /* Free OpenSSL error strings */
+ ERR_free_strings();
+
+ /* Free thread local error state, destroying hash upon zero refcount */
+#ifdef HAVE_ERR_REMOVE_THREAD_STATE
+ ERR_remove_thread_state(NULL);
+#else
+ ERR_remove_state(0);
+#endif
+}
+
+/*
+ * This function uses SSL_peek to determine connection status.
+ *
+ * Return codes:
+ * 1 means the connection is still in place
+ * 0 means the connection has been closed
+ * -1 means the connection status is unknown
+ */
+int Curl_ossl_check_cxn(struct connectdata *conn)
+{
+ int rc;
+ char buf;
+
+ rc = SSL_peek(conn->ssl[FIRSTSOCKET].handle, (void*)&buf, 1);
+ if(rc > 0)
+ return 1; /* connection still in place */
+
+ if(rc == 0)
+ return 0; /* connection has been closed */
+
+ return -1; /* connection status unknown */
+}
+
+/* Selects an OpenSSL crypto engine
+ */
+CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine)
+{
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+ ENGINE *e;
+
+#if OPENSSL_VERSION_NUMBER >= 0x00909000L
+ e = ENGINE_by_id(engine);
+#else
+ /* avoid memory leak */
+ for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+ const char *e_id = ENGINE_get_id(e);
+ if(!strcmp(engine, e_id))
+ break;
+ }
+#endif
+
+ if(!e) {
+ failf(data, "SSL Engine '%s' not found", engine);
+ return CURLE_SSL_ENGINE_NOTFOUND;
+ }
+
+ if(data->state.engine) {
+ ENGINE_finish(data->state.engine);
+ ENGINE_free(data->state.engine);
+ data->state.engine = NULL;
+ }
+ if(!ENGINE_init(e)) {
+ char buf[256];
+
+ ENGINE_free(e);
+ failf(data, "Failed to initialise SSL Engine '%s':\n%s",
+ engine, SSL_strerror(ERR_get_error(), buf, sizeof(buf)));
+ return CURLE_SSL_ENGINE_INITFAILED;
+ }
+ data->state.engine = e;
+ return CURLE_OK;
+#else
+ (void)engine;
+ failf(data, "SSL Engine not supported");
+ return CURLE_SSL_ENGINE_NOTFOUND;
+#endif
+}
+
+/* Sets engine as default for all SSL operations
+ */
+CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data)
+{
+#ifdef HAVE_OPENSSL_ENGINE_H
+ if(data->state.engine) {
+ if(ENGINE_set_default(data->state.engine, ENGINE_METHOD_ALL) > 0) {
+ infof(data,"set default crypto engine '%s'\n",
+ ENGINE_get_id(data->state.engine));
+ }
+ else {
+ failf(data, "set default crypto engine '%s' failed",
+ ENGINE_get_id(data->state.engine));
+ return CURLE_SSL_ENGINE_SETFAILED;
+ }
+ }
+#else
+ (void) data;
+#endif
+ return CURLE_OK;
+}
+
+/* Return list of OpenSSL crypto engine names.
+ */
+struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data)
+{
+ struct curl_slist *list = NULL;
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+ struct curl_slist *beg;
+ ENGINE *e;
+
+ for(e = ENGINE_get_first(); e; e = ENGINE_get_next(e)) {
+ beg = curl_slist_append(list, ENGINE_get_id(e));
+ if(!beg) {
+ curl_slist_free_all(list);
+ return NULL;
+ }
+ list = beg;
+ }
+#endif
+ (void) data;
+ return list;
+}
+
+
+/*
+ * This function is called when an SSL connection is closed.
+ */
+void Curl_ossl_close(struct connectdata *conn, int sockindex)
+{
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ if(connssl->handle) {
+ (void)SSL_shutdown(connssl->handle);
+ SSL_set_connect_state(connssl->handle);
+
+ SSL_free (connssl->handle);
+ connssl->handle = NULL;
+ }
+ if(connssl->ctx) {
+ SSL_CTX_free (connssl->ctx);
+ connssl->ctx = NULL;
+ }
+}
+
+/*
+ * This function is called to shut down the SSL layer but keep the
+ * socket open (CCC - Clear Command Channel)
+ */
+int Curl_ossl_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. */
+ unsigned long sslerror;
+ ssize_t nread;
+ int buffsize;
+ int err;
+ int done = 0;
+
+ /* This has only been tested on the proftpd server, and the mod_tls code
+ sends a close notify alert without waiting for a close notify alert in
+ response. Thus we wait for a close notify alert from the server, but
+ we do not send one. Let's hope other servers do the same... */
+
+ if(data->set.ftp_ccc == CURLFTPSSL_CCC_ACTIVE)
+ (void)SSL_shutdown(connssl->handle);
+
+ if(connssl->handle) {
+ buffsize = sizeof(buf);
+ while(!done) {
+ int what = Curl_socket_ready(conn->sock[sockindex],
+ CURL_SOCKET_BAD, SSL_SHUTDOWN_TIMEOUT);
+ if(what > 0) {
+ ERR_clear_error();
+
+ /* 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].handle, buf,
+ buffsize);
+ err = SSL_get_error(conn->ssl[sockindex].handle, (int)nread);
+
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ /* This is the expected response. There was no data but only
+ the close notify alert */
+ done = 1;
+ break;
+ case SSL_ERROR_WANT_READ:
+ /* there's data pending, re-invoke SSL_read() */
+ infof(data, "SSL_ERROR_WANT_READ\n");
+ break;
+ case SSL_ERROR_WANT_WRITE:
+ /* SSL wants a write. Really odd. Let's bail out. */
+ infof(data, "SSL_ERROR_WANT_WRITE\n");
+ done = 1;
+ break;
+ default:
+ /* openssl/ssl.h says "look at error stack/return value/errno" */
+ sslerror = ERR_get_error();
+ failf(conn->data, "SSL read: %s, errno %d",
+ ERR_error_string(sslerror, buf),
+ SOCKERRNO);
+ done = 1;
+ break;
+ }
+ }
+ else if(0 == what) {
+ /* timeout */
+ failf(data, "SSL shutdown timeout");
+ done = 1;
+ }
+ else {
+ /* anything that gets here is fatally bad */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ retval = -1;
+ done = 1;
+ }
+ } /* while()-loop for the select() */
+
+ if(data->set.verbose) {
+#ifdef HAVE_SSL_GET_SHUTDOWN
+ switch(SSL_get_shutdown(connssl->handle)) {
+ case SSL_SENT_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN\n");
+ break;
+ case SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_RECEIVED_SHUTDOWN\n");
+ break;
+ case SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN:
+ infof(data, "SSL_get_shutdown() returned SSL_SENT_SHUTDOWN|"
+ "SSL_RECEIVED__SHUTDOWN\n");
+ break;
+ }
+#endif
+ }
+
+ SSL_free (connssl->handle);
+ connssl->handle = NULL;
+ }
+ return retval;
+}
+
+void Curl_ossl_session_free(void *ptr)
+{
+ /* free the ID */
+ SSL_SESSION_free(ptr);
+}
+
+/*
+ * This function is called when the 'data' struct is going away. Close
+ * down everything and free all resources!
+ */
+int Curl_ossl_close_all(struct SessionHandle *data)
+{
+#ifdef HAVE_OPENSSL_ENGINE_H
+ if(data->state.engine) {
+ ENGINE_finish(data->state.engine);
+ ENGINE_free(data->state.engine);
+ data->state.engine = NULL;
+ }
+#else
+ (void)data;
+#endif
+ return 0;
+}
+
+static int asn1_output(const ASN1_UTCTIME *tm,
+ char *buf,
+ size_t sizeofbuf)
+{
+ const char *asn1_string;
+ int gmt=FALSE;
+ int i;
+ int year=0,month=0,day=0,hour=0,minute=0,second=0;
+
+ i=tm->length;
+ asn1_string=(const char *)tm->data;
+
+ if(i < 10)
+ return 1;
+ if(asn1_string[i-1] == 'Z')
+ gmt=TRUE;
+ for(i=0; i<10; i++)
+ if((asn1_string[i] > '9') || (asn1_string[i] < '0'))
+ return 2;
+
+ year= (asn1_string[0]-'0')*10+(asn1_string[1]-'0');
+ if(year < 50)
+ year+=100;
+
+ month= (asn1_string[2]-'0')*10+(asn1_string[3]-'0');
+ if((month > 12) || (month < 1))
+ return 3;
+
+ day= (asn1_string[4]-'0')*10+(asn1_string[5]-'0');
+ hour= (asn1_string[6]-'0')*10+(asn1_string[7]-'0');
+ minute= (asn1_string[8]-'0')*10+(asn1_string[9]-'0');
+
+ if((asn1_string[10] >= '0') && (asn1_string[10] <= '9') &&
+ (asn1_string[11] >= '0') && (asn1_string[11] <= '9'))
+ second= (asn1_string[10]-'0')*10+(asn1_string[11]-'0');
+
+ snprintf(buf, sizeofbuf,
+ "%04d-%02d-%02d %02d:%02d:%02d %s",
+ year+1900, month, day, hour, minute, second, (gmt?"GMT":""));
+
+ return 0;
+}
+
+/* ====================================================== */
+
+
+/* Quote from RFC2818 section 3.1 "Server Identity"
+
+ If a subjectAltName extension of type dNSName is present, that MUST
+ be used as the identity. Otherwise, the (most specific) Common Name
+ field in the Subject field of the certificate MUST be used. Although
+ the use of the Common Name is existing practice, it is deprecated and
+ Certification Authorities are encouraged to use the dNSName instead.
+
+ Matching is performed using the matching rules specified by
+ [RFC2459]. If more than one identity of a given type is present in
+ the certificate (e.g., more than one dNSName name, a match in any one
+ of the set is considered acceptable.) Names may contain the wildcard
+ character * which is considered to match any single domain name
+ component or component fragment. E.g., *.a.com matches foo.a.com but
+ not bar.foo.a.com. f*.com matches foo.com but not bar.com.
+
+ In some cases, the URI is specified as an IP address rather than a
+ hostname. In this case, the iPAddress subjectAltName must be present
+ in the certificate and must exactly match the IP in the URI.
+
+*/
+static CURLcode verifyhost(struct connectdata *conn,
+ X509 *server_cert)
+{
+ int matched = -1; /* -1 is no alternative match yet, 1 means match and 0
+ means mismatch */
+ int target = GEN_DNS; /* target type, GEN_DNS or GEN_IPADD */
+ size_t addrlen = 0;
+ struct SessionHandle *data = conn->data;
+ STACK_OF(GENERAL_NAME) *altnames;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+ CURLcode res = CURLE_OK;
+
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip &&
+ Curl_inet_pton(AF_INET6, conn->host.name, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in6_addr);
+ }
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, conn->host.name, &addr)) {
+ target = GEN_IPADD;
+ addrlen = sizeof(struct in_addr);
+ }
+
+ /* get a "list" of alternative names */
+ altnames = X509_get_ext_d2i(server_cert, NID_subject_alt_name, NULL, NULL);
+
+ if(altnames) {
+ int numalts;
+ int i;
+
+ /* get amount of alternatives, RFC2459 claims there MUST be at least
+ one, but we don't depend on it... */
+ numalts = sk_GENERAL_NAME_num(altnames);
+
+ /* loop through all alternatives while none has matched */
+ for(i=0; (i<numalts) && (matched != 1); i++) {
+ /* get a handle to alternative name number i */
+ const GENERAL_NAME *check = sk_GENERAL_NAME_value(altnames, i);
+
+ /* only check alternatives of the same type the target is */
+ if(check->type == target) {
+ /* get data and length */
+ const char *altptr = (char *)ASN1_STRING_data(check->d.ia5);
+ size_t altlen = (size_t) ASN1_STRING_length(check->d.ia5);
+
+ switch(target) {
+ case GEN_DNS: /* name/pattern comparison */
+ /* The OpenSSL man page explicitly says: "In general it cannot be
+ assumed that the data returned by ASN1_STRING_data() is null
+ terminated or does not contain embedded nulls." But also that
+ "The actual format of the data will depend on the actual string
+ type itself: for example for and IA5String the data will be ASCII"
+
+ Gisle researched the OpenSSL sources:
+ "I checked the 0.9.6 and 0.9.8 sources before my patch and
+ it always 0-terminates an IA5String."
+ */
+ if((altlen == strlen(altptr)) &&
+ /* if this isn't true, there was an embedded zero in the name
+ string and we cannot match it. */
+ Curl_cert_hostcheck(altptr, conn->host.name))
+ matched = 1;
+ else
+ matched = 0;
+ break;
+
+ case GEN_IPADD: /* IP address comparison */
+ /* compare alternative IP address if the data chunk is the same size
+ our server IP address is */
+ if((altlen == addrlen) && !memcmp(altptr, &addr, altlen))
+ matched = 1;
+ else
+ matched = 0;
+ break;
+ }
+ }
+ }
+ GENERAL_NAMES_free(altnames);
+ }
+
+ if(matched == 1)
+ /* an alternative name matched the server hostname */
+ infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+ else if(matched == 0) {
+ /* an alternative name field existed, but didn't match and then
+ we MUST fail */
+ infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
+ failf(data, "SSL: no alternative certificate subject name matches "
+ "target host name '%s'", conn->host.dispname);
+ res = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ /* we have to look to the last occurrence of a commonName in the
+ distinguished one to get the most significant one. */
+ int j,i=-1 ;
+
+/* The following is done because of a bug in 0.9.6b */
+
+ unsigned char *nulstr = (unsigned char *)"";
+ unsigned char *peer_CN = nulstr;
+
+ X509_NAME *name = X509_get_subject_name(server_cert) ;
+ if(name)
+ while((j = X509_NAME_get_index_by_NID(name, NID_commonName, i))>=0)
+ i=j;
+
+ /* we have the name entry and we will now convert this to a string
+ that we can use for comparison. Doing this we support BMPstring,
+ UTF8 etc. */
+
+ if(i>=0) {
+ ASN1_STRING *tmp = X509_NAME_ENTRY_get_data(X509_NAME_get_entry(name,i));
+
+ /* In OpenSSL 0.9.7d and earlier, ASN1_STRING_to_UTF8 fails if the input
+ is already UTF-8 encoded. We check for this case and copy the raw
+ string manually to avoid the problem. This code can be made
+ conditional in the future when OpenSSL has been fixed. Work-around
+ brought by Alexis S. L. Carvalho. */
+ if(tmp) {
+ if(ASN1_STRING_type(tmp) == V_ASN1_UTF8STRING) {
+ j = ASN1_STRING_length(tmp);
+ if(j >= 0) {
+ peer_CN = OPENSSL_malloc(j+1);
+ if(peer_CN) {
+ memcpy(peer_CN, ASN1_STRING_data(tmp), j);
+ peer_CN[j] = '\0';
+ }
+ }
+ }
+ else /* not a UTF8 name */
+ j = ASN1_STRING_to_UTF8(&peer_CN, tmp);
+
+ if(peer_CN && (curlx_uztosi(strlen((char *)peer_CN)) != j)) {
+ /* there was a terminating zero before the end of string, this
+ cannot match and we return failure! */
+ failf(data, "SSL: illegal cert name field");
+ res = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ }
+ }
+
+ if(peer_CN == nulstr)
+ peer_CN = NULL;
+ else {
+ /* convert peer_CN from UTF8 */
+ CURLcode rc = Curl_convert_from_utf8(data, peer_CN, strlen(peer_CN));
+ /* Curl_convert_from_utf8 calls failf if unsuccessful */
+ if(rc) {
+ OPENSSL_free(peer_CN);
+ return rc;
+ }
+ }
+
+ if(res)
+ /* error already detected, pass through */
+ ;
+ else if(!peer_CN) {
+ failf(data,
+ "SSL: unable to obtain common name from peer certificate");
+ res = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else if(!Curl_cert_hostcheck((const char *)peer_CN, conn->host.name)) {
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", peer_CN, conn->host.dispname);
+ res = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else {
+ infof(data, "\t common name: %s (matched)\n", peer_CN);
+ }
+ if(peer_CN)
+ OPENSSL_free(peer_CN);
+ }
+ return res;
+}
+#endif /* USE_SSLEAY */
+
+/* The SSL_CTRL_SET_MSG_CALLBACK doesn't exist in ancient OpenSSL versions
+ and thus this cannot be done there. */
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+
+static const char *ssl_msg_type(int ssl_ver, int msg)
+{
+ if(ssl_ver == SSL2_VERSION_MAJOR) {
+ switch (msg) {
+ case SSL2_MT_ERROR:
+ return "Error";
+ case SSL2_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL2_MT_CLIENT_MASTER_KEY:
+ return "Client key";
+ case SSL2_MT_CLIENT_FINISHED:
+ return "Client finished";
+ case SSL2_MT_SERVER_HELLO:
+ return "Server hello";
+ case SSL2_MT_SERVER_VERIFY:
+ return "Server verify";
+ case SSL2_MT_SERVER_FINISHED:
+ return "Server finished";
+ case SSL2_MT_REQUEST_CERTIFICATE:
+ return "Request CERT";
+ case SSL2_MT_CLIENT_CERTIFICATE:
+ return "Client CERT";
+ }
+ }
+ else if(ssl_ver == SSL3_VERSION_MAJOR) {
+ switch (msg) {
+ case SSL3_MT_HELLO_REQUEST:
+ return "Hello request";
+ case SSL3_MT_CLIENT_HELLO:
+ return "Client hello";
+ case SSL3_MT_SERVER_HELLO:
+ return "Server hello";
+ case SSL3_MT_CERTIFICATE:
+ return "CERT";
+ case SSL3_MT_SERVER_KEY_EXCHANGE:
+ return "Server key exchange";
+ case SSL3_MT_CLIENT_KEY_EXCHANGE:
+ return "Client key exchange";
+ case SSL3_MT_CERTIFICATE_REQUEST:
+ return "Request CERT";
+ case SSL3_MT_SERVER_DONE:
+ return "Server finished";
+ case SSL3_MT_CERTIFICATE_VERIFY:
+ return "CERT verify";
+ case SSL3_MT_FINISHED:
+ return "Finished";
+ }
+ }
+ return "Unknown";
+}
+
+static const char *tls_rt_type(int type)
+{
+ return (
+ type == SSL3_RT_CHANGE_CIPHER_SPEC ? "TLS change cipher, " :
+ type == SSL3_RT_ALERT ? "TLS alert, " :
+ type == SSL3_RT_HANDSHAKE ? "TLS handshake, " :
+ type == SSL3_RT_APPLICATION_DATA ? "TLS app data, " :
+ "TLS Unknown, ");
+}
+
+
+/*
+ * Our callback from the SSL/TLS layers.
+ */
+static void ssl_tls_trace(int direction, int ssl_ver, int content_type,
+ const void *buf, size_t len, const SSL *ssl,
+ struct connectdata *conn)
+{
+ struct SessionHandle *data;
+ const char *msg_name, *tls_rt_name;
+ char ssl_buf[1024];
+ int ver, msg_type, txt_len;
+
+ if(!conn || !conn->data || !conn->data->set.fdebug ||
+ (direction != 0 && direction != 1))
+ return;
+
+ data = conn->data;
+ ssl_ver >>= 8;
+ ver = (ssl_ver == SSL2_VERSION_MAJOR ? '2' :
+ ssl_ver == SSL3_VERSION_MAJOR ? '3' : '?');
+
+ /* SSLv2 doesn't seem to have TLS record-type headers, so OpenSSL
+ * always pass-up content-type as 0. But the interesting message-type
+ * is at 'buf[0]'.
+ */
+ if(ssl_ver == SSL3_VERSION_MAJOR && content_type != 0)
+ tls_rt_name = tls_rt_type(content_type);
+ else
+ tls_rt_name = "";
+
+ msg_type = *(char*)buf;
+ msg_name = ssl_msg_type(ssl_ver, msg_type);
+
+ txt_len = snprintf(ssl_buf, sizeof(ssl_buf), "SSLv%c, %s%s (%d):\n",
+ ver, tls_rt_name, msg_name, msg_type);
+ Curl_debug(data, CURLINFO_TEXT, ssl_buf, (size_t)txt_len, NULL);
+
+ Curl_debug(data, (direction == 1) ? CURLINFO_SSL_DATA_OUT :
+ CURLINFO_SSL_DATA_IN, (char *)buf, len, NULL);
+ (void) ssl;
+}
+#endif
+
+#ifdef USE_SSLEAY
+/* ====================================================== */
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+# define use_sni(x) sni = (x)
+#else
+# define use_sni(x) Curl_nop_stmt
+#endif
+
+static CURLcode
+ossl_connect_step1(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+
+ struct SessionHandle *data = conn->data;
+ SSL_METHOD_QUAL SSL_METHOD *req_method=NULL;
+ void *ssl_sessionid=NULL;
+ X509_LOOKUP *lookup=NULL;
+ curl_socket_t sockfd = conn->sock[sockindex];
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ long ctx_options;
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ bool sni;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+#endif
+
+ DEBUGASSERT(ssl_connect_1 == connssl->connecting_state);
+
+ /* Make funny stuff to get random input */
+ Curl_ossl_seed(data);
+
+ /* check to see if we've been told to use an explicit SSL/TLS version */
+
+ switch(data->set.ssl.version) {
+ default:
+ case CURL_SSLVERSION_DEFAULT:
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ infof(data, "Set version TLSv1 for SRP authorisation\n");
+ req_method = TLSv1_client_method() ;
+ }
+ else
+#endif
+ /* we try to figure out version */
+ req_method = SSLv23_client_method();
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_TLSv1:
+ req_method = TLSv1_client_method();
+ use_sni(TRUE);
+ break;
+ case CURL_SSLVERSION_SSLv2:
+#ifdef OPENSSL_NO_SSL2
+ failf(data, "OpenSSL was built without SSLv2 support");
+ return CURLE_NOT_BUILT_IN;
+#else
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ req_method = SSLv2_client_method();
+ use_sni(FALSE);
+ break;
+#endif
+ case CURL_SSLVERSION_SSLv3:
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP)
+ return CURLE_SSL_CONNECT_ERROR;
+#endif
+ req_method = SSLv3_client_method();
+ use_sni(FALSE);
+ break;
+ }
+
+ if(connssl->ctx)
+ SSL_CTX_free(connssl->ctx);
+ connssl->ctx = SSL_CTX_new(req_method);
+
+ if(!connssl->ctx) {
+ failf(data, "SSL: couldn't create a context: %s",
+ ERR_error_string(ERR_peek_error(), NULL));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+#ifdef SSL_MODE_RELEASE_BUFFERS
+ SSL_CTX_set_mode(connssl->ctx, SSL_MODE_RELEASE_BUFFERS);
+#endif
+
+#ifdef SSL_CTRL_SET_MSG_CALLBACK
+ if(data->set.fdebug && data->set.verbose) {
+ /* the SSL trace callback is only used for verbose logging so we only
+ inform about failures of setting it */
+ if(!SSL_CTX_callback_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK,
+ (void (*)(void))ssl_tls_trace)) {
+ infof(data, "SSL: couldn't set callback!\n");
+ }
+ else if(!SSL_CTX_ctrl(connssl->ctx, SSL_CTRL_SET_MSG_CALLBACK_ARG, 0,
+ conn)) {
+ infof(data, "SSL: couldn't set callback argument!\n");
+ }
+ }
+#endif
+
+ /* OpenSSL contains code to work-around lots of bugs and flaws in various
+ SSL-implementations. SSL_CTX_set_options() is used to enabled those
+ work-arounds. The man page for this option states that SSL_OP_ALL enables
+ all the work-arounds and that "It is usually safe to use SSL_OP_ALL to
+ enable the bug workaround options if compatibility with somewhat broken
+ implementations is desired."
+
+ The "-no_ticket" option was introduced in Openssl0.9.8j. It's a flag to
+ disable "rfc4507bis session ticket support". rfc4507bis was later turned
+ into the proper RFC5077 it seems: http://tools.ietf.org/html/rfc5077
+
+ The enabled extension concerns the session management. I wonder how often
+ libcurl stops a connection and then resumes a TLS session. also, sending
+ the session data is some overhead. .I suggest that you just use your
+ proposed patch (which explicitly disables TICKET).
+
+ If someone writes an application with libcurl and openssl who wants to
+ enable the feature, one can do this in the SSL callback.
+
+ SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG option enabling allowed proper
+ interoperability with web server Netscape Enterprise Server 2.0.1 which
+ was released back in 1996.
+
+ Due to CVE-2010-4180, option SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG has
+ become ineffective as of OpenSSL 0.9.8q and 1.0.0c. In order to mitigate
+ CVE-2010-4180 when using previous OpenSSL versions we no longer enable
+ this option regardless of OpenSSL version and SSL_OP_ALL definition.
+
+ OpenSSL added a work-around for a SSL 3.0/TLS 1.0 CBC vulnerability
+ (http://www.openssl.org/~bodo/tls-cbc.txt). In 0.9.6e they added a bit to
+ SSL_OP_ALL that _disables_ that work-around despite the fact that
+ SSL_OP_ALL is documented to do "rather harmless" workarounds. In order to
+ keep the secure work-around, the SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS bit
+ must not be set.
+ */
+
+ ctx_options = SSL_OP_ALL;
+
+#ifdef SSL_OP_NO_TICKET
+ ctx_options |= SSL_OP_NO_TICKET;
+#endif
+
+#ifdef SSL_OP_NO_COMPRESSION
+ ctx_options |= SSL_OP_NO_COMPRESSION;
+#endif
+
+#ifdef SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG
+ /* mitigate CVE-2010-4180 */
+ ctx_options &= ~SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+#endif
+
+#ifdef SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS
+ /* unless the user explicitly ask to allow the protocol vulnerability we
+ use the work-around */
+ if(!conn->data->set.ssl_enable_beast)
+ ctx_options &= ~SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+#endif
+
+ /* disable SSLv2 in the default case (i.e. allow SSLv3 and TLSv1) */
+ if(data->set.ssl.version == CURL_SSLVERSION_DEFAULT)
+ ctx_options |= SSL_OP_NO_SSLv2;
+
+ SSL_CTX_set_options(connssl->ctx, ctx_options);
+
+ if(data->set.str[STRING_CERT] || data->set.str[STRING_CERT_TYPE]) {
+ if(!cert_stuff(conn,
+ connssl->ctx,
+ data->set.str[STRING_CERT],
+ data->set.str[STRING_CERT_TYPE],
+ data->set.str[STRING_KEY],
+ data->set.str[STRING_KEY_TYPE])) {
+ /* failf() is already done in cert_stuff() */
+ return CURLE_SSL_CERTPROBLEM;
+ }
+ }
+
+ if(data->set.str[STRING_SSL_CIPHER_LIST]) {
+ if(!SSL_CTX_set_cipher_list(connssl->ctx,
+ data->set.str[STRING_SSL_CIPHER_LIST])) {
+ failf(data, "failed setting cipher list");
+ return CURLE_SSL_CIPHER;
+ }
+ }
+
+#ifdef USE_TLS_SRP
+ if(data->set.ssl.authtype == CURL_TLSAUTH_SRP) {
+ infof(data, "Using TLS-SRP username: %s\n", data->set.ssl.username);
+
+ if(!SSL_CTX_set_srp_username(connssl->ctx, data->set.ssl.username)) {
+ failf(data, "Unable to set SRP user name");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ if(!SSL_CTX_set_srp_password(connssl->ctx,data->set.ssl.password)) {
+ failf(data, "failed setting SRP password");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+ if(!data->set.str[STRING_SSL_CIPHER_LIST]) {
+ infof(data, "Setting cipher list SRP\n");
+
+ if(!SSL_CTX_set_cipher_list(connssl->ctx, "SRP")) {
+ failf(data, "failed setting SRP cipher list");
+ return CURLE_SSL_CIPHER;
+ }
+ }
+ }
+#endif
+ if(data->set.str[STRING_SSL_CAFILE] || data->set.str[STRING_SSL_CAPATH]) {
+ /* tell SSL where to find CA certificates that are used to verify
+ the servers certificate. */
+ if(!SSL_CTX_load_verify_locations(connssl->ctx,
+ data->set.str[STRING_SSL_CAFILE],
+ data->set.str[STRING_SSL_CAPATH])) {
+ if(data->set.ssl.verifypeer) {
+ /* Fail if we insist on successfully verifying the server. */
+ failf(data,"error setting certificate verify locations:\n"
+ " CAfile: %s\n CApath: %s",
+ data->set.str[STRING_SSL_CAFILE]?
+ data->set.str[STRING_SSL_CAFILE]: "none",
+ data->set.str[STRING_SSL_CAPATH]?
+ data->set.str[STRING_SSL_CAPATH] : "none");
+ return CURLE_SSL_CACERT_BADFILE;
+ }
+ else {
+ /* Just continue with a warning if no strict certificate verification
+ is required. */
+ infof(data, "error setting certificate verify locations,"
+ " continuing anyway:\n");
+ }
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully set certificate verify locations:\n");
+ }
+ infof(data,
+ " CAfile: %s\n"
+ " CApath: %s\n",
+ data->set.str[STRING_SSL_CAFILE] ? data->set.str[STRING_SSL_CAFILE]:
+ "none",
+ data->set.str[STRING_SSL_CAPATH] ? data->set.str[STRING_SSL_CAPATH]:
+ "none");
+ }
+
+ if(data->set.str[STRING_SSL_CRLFILE]) {
+ /* tell SSL where to find CRL file that is used to check certificate
+ * revocation */
+ lookup=X509_STORE_add_lookup(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_LOOKUP_file());
+ if(!lookup ||
+ (!X509_load_crl_file(lookup,data->set.str[STRING_SSL_CRLFILE],
+ X509_FILETYPE_PEM)) ) {
+ failf(data,"error loading CRL file: %s",
+ data->set.str[STRING_SSL_CRLFILE]);
+ return CURLE_SSL_CRL_BADFILE;
+ }
+ else {
+ /* Everything is fine. */
+ infof(data, "successfully load CRL file:\n");
+ X509_STORE_set_flags(SSL_CTX_get_cert_store(connssl->ctx),
+ X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL);
+ }
+ infof(data,
+ " CRLfile: %s\n", data->set.str[STRING_SSL_CRLFILE] ?
+ data->set.str[STRING_SSL_CRLFILE]: "none");
+ }
+
+ /* 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. */
+ SSL_CTX_set_verify(connssl->ctx,
+ data->set.ssl.verifypeer?SSL_VERIFY_PEER:SSL_VERIFY_NONE,
+ cert_verify_callback);
+
+ /* give application a chance to interfere with SSL set up. */
+ if(data->set.ssl.fsslctx) {
+ retcode = (*data->set.ssl.fsslctx)(data, connssl->ctx,
+ data->set.ssl.fsslctxp);
+ if(retcode) {
+ failf(data,"error signaled by ssl ctx callback");
+ return retcode;
+ }
+ }
+
+ /* Lets make an SSL structure */
+ if(connssl->handle)
+ SSL_free(connssl->handle);
+ connssl->handle = SSL_new(connssl->ctx);
+ if(!connssl->handle) {
+ failf(data, "SSL: couldn't create a context (handle)!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ SSL_set_connect_state(connssl->handle);
+
+ connssl->server_cert = 0x0;
+
+#ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME
+ if((0 == Curl_inet_pton(AF_INET, conn->host.name, &addr)) &&
+#ifdef ENABLE_IPV6
+ (0 == Curl_inet_pton(AF_INET6, conn->host.name, &addr)) &&
+#endif
+ sni &&
+ !SSL_set_tlsext_host_name(connssl->handle, conn->host.name))
+ infof(data, "WARNING: failed to configure server name indication (SNI) "
+ "TLS extension\n");
+#endif
+
+ /* Check if there's a cached ID we can/should use here! */
+ if(!Curl_ssl_getsessionid(conn, &ssl_sessionid, NULL)) {
+ /* we got a session id, use it! */
+ if(!SSL_set_session(connssl->handle, ssl_sessionid)) {
+ failf(data, "SSL: SSL_set_session failed: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ /* Informational message */
+ infof (data, "SSL re-using session ID\n");
+ }
+
+ /* pass the raw socket into the SSL layers */
+ if(!SSL_set_fd(connssl->handle, (int)sockfd)) {
+ failf(data, "SSL: SSL_set_fd failed: %s",
+ ERR_error_string(ERR_get_error(),NULL));
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+
+ connssl->connecting_state = ssl_connect_2;
+ return CURLE_OK;
+}
+
+static CURLcode
+ossl_connect_step2(struct connectdata *conn, int sockindex)
+{
+ struct SessionHandle *data = conn->data;
+ int err;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+
+ DEBUGASSERT(ssl_connect_2 == connssl->connecting_state
+ || ssl_connect_2_reading == connssl->connecting_state
+ || ssl_connect_2_writing == connssl->connecting_state);
+
+ ERR_clear_error();
+
+ err = SSL_connect(connssl->handle);
+
+ /* 1 is fine
+ 0 is "not successful but was shut down controlled"
+ <0 is "handshake was not successful, because a fatal error occurred" */
+ if(1 != err) {
+ int detail = SSL_get_error(connssl->handle, err);
+
+ if(SSL_ERROR_WANT_READ == detail) {
+ connssl->connecting_state = ssl_connect_2_reading;
+ return CURLE_OK;
+ }
+ else if(SSL_ERROR_WANT_WRITE == detail) {
+ connssl->connecting_state = ssl_connect_2_writing;
+ return CURLE_OK;
+ }
+ else {
+ /* untreated error */
+ unsigned long errdetail;
+ char error_buffer[256]; /* OpenSSL documents that this must be at least
+ 256 bytes long. */
+ CURLcode rc;
+ const char *cert_problem = NULL;
+ long lerr;
+
+ connssl->connecting_state = ssl_connect_2; /* the connection failed,
+ we're not waiting for
+ anything else. */
+
+ errdetail = ERR_get_error(); /* Gets the earliest error code from the
+ thread's error queue and removes the
+ entry. */
+
+ switch(errdetail) {
+ case 0x1407E086:
+ /* 1407E086:
+ SSL routines:
+ SSL2_SET_CERTIFICATE:
+ certificate verify failed */
+ /* fall-through */
+ case 0x14090086:
+ /* 14090086:
+ SSL routines:
+ SSL3_GET_SERVER_CERTIFICATE:
+ certificate verify failed */
+ rc = CURLE_SSL_CACERT;
+
+ lerr = SSL_get_verify_result(connssl->handle);
+ if(lerr != X509_V_OK) {
+ snprintf(error_buffer, sizeof(error_buffer),
+ "SSL certificate problem: %s",
+ X509_verify_cert_error_string(lerr));
+ }
+ else
+ cert_problem = "SSL certificate problem, verify that the CA cert is"
+ " OK.";
+
+ break;
+ default:
+ rc = CURLE_SSL_CONNECT_ERROR;
+ SSL_strerror(errdetail, error_buffer, sizeof(error_buffer));
+ break;
+ }
+
+ /* detail is already set to the SSL error above */
+
+ /* If we e.g. use SSLv2 request-method and the server doesn't like us
+ * (RST connection etc.), OpenSSL gives no explanation whatsoever and
+ * the SO_ERROR is also lost.
+ */
+ if(CURLE_SSL_CONNECT_ERROR == rc && errdetail == 0) {
+ failf(data, "Unknown SSL protocol error in connection to %s:%ld ",
+ conn->host.name, conn->remote_port);
+ return rc;
+ }
+ /* Could be a CERT problem */
+
+ failf(data, "%s%s", cert_problem ? cert_problem : "", error_buffer);
+ return rc;
+ }
+ }
+ else {
+ /* we have been connected fine, we're not waiting for anything else. */
+ connssl->connecting_state = ssl_connect_3;
+
+ /* Informational message */
+ infof (data, "SSL connection using %s\n",
+ SSL_get_cipher(connssl->handle));
+
+ return CURLE_OK;
+ }
+}
+
+static int asn1_object_dump(ASN1_OBJECT *a, char *buf, size_t len)
+{
+ int i, ilen;
+
+ if((ilen = (int)len) < 0)
+ return 1; /* buffer too big */
+
+ i = i2t_ASN1_OBJECT(buf, ilen, a);
+
+ if(i >= ilen)
+ return 1; /* buffer too small */
+
+ return 0;
+}
+
+static void pubkey_show(struct SessionHandle *data,
+ int num,
+ const char *type,
+ const char *name,
+ unsigned char *raw,
+ int len)
+{
+ size_t left;
+ int i;
+ char namebuf[32];
+ char *buffer;
+
+ left = len*3 + 1;
+ buffer = malloc(left);
+ if(buffer) {
+ char *ptr=buffer;
+ snprintf(namebuf, sizeof(namebuf), "%s(%s)", type, name);
+ for(i=0; i< len; i++) {
+ snprintf(ptr, left, "%02x:", raw[i]);
+ ptr += 3;
+ left -= 3;
+ }
+ infof(data, " %s: %s\n", namebuf, buffer);
+ Curl_ssl_push_certinfo(data, num, namebuf, buffer);
+ free(buffer);
+ }
+}
+
+#define print_pubkey_BN(_type, _name, _num) \
+do { \
+ if(pubkey->pkey._type->_name != NULL) { \
+ int len = BN_num_bytes(pubkey->pkey._type->_name); \
+ if(len < CERTBUFFERSIZE) { \
+ BN_bn2bin(pubkey->pkey._type->_name, (unsigned char*)bufp); \
+ bufp[len] = 0; \
+ pubkey_show(data, _num, #_type, #_name, (unsigned char*)bufp, len); \
+ } \
+ } \
+} WHILE_FALSE
+
+static int X509V3_ext(struct SessionHandle *data,
+ int certnum,
+ STACK_OF(X509_EXTENSION) *exts)
+{
+ int i;
+ size_t j;
+
+ if(sk_X509_EXTENSION_num(exts) <= 0)
+ /* no extensions, bail out */
+ return 1;
+
+ for(i=0; i<sk_X509_EXTENSION_num(exts); i++) {
+ ASN1_OBJECT *obj;
+ X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i);
+ BUF_MEM *biomem;
+ char buf[512];
+ char *ptr=buf;
+ char namebuf[128];
+ BIO *bio_out = BIO_new(BIO_s_mem());
+
+ if(!bio_out)
+ return 1;
+
+ obj = X509_EXTENSION_get_object(ext);
+
+ asn1_object_dump(obj, namebuf, sizeof(namebuf));
+
+ infof(data, "%s: %s\n", namebuf,
+ X509_EXTENSION_get_critical(ext)?"(critical)":"");
+
+ if(!X509V3_EXT_print(bio_out, ext, 0, 0))
+ M_ASN1_OCTET_STRING_print(bio_out, ext->value);
+
+ BIO_get_mem_ptr(bio_out, &biomem);
+
+ /* biomem->length bytes at biomem->data, this little loop here is only
+ done for the infof() call, we send the "raw" data to the certinfo
+ function */
+ for(j=0; j<(size_t)biomem->length; j++) {
+ const char *sep="";
+ if(biomem->data[j] == '\n') {
+ sep=", ";
+ j++; /* skip the newline */
+ };
+ while((biomem->data[j] == ' ') && (j<(size_t)biomem->length))
+ j++;
+ if(j<(size_t)biomem->length)
+ ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%s%c", sep,
+ biomem->data[j]);
+ }
+ infof(data, " %s\n", buf);
+
+ Curl_ssl_push_certinfo(data, certnum, namebuf, buf);
+
+ BIO_free(bio_out);
+
+ }
+ return 0; /* all is fine */
+}
+
+
+static void X509_signature(struct SessionHandle *data,
+ int numcert,
+ ASN1_STRING *sig)
+{
+ char buf[1024];
+ char *ptr = buf;
+ int i;
+ for(i=0; i<sig->length; i++)
+ ptr+=snprintf(ptr, sizeof(buf)-(ptr-buf), "%02x:", sig->data[i]);
+
+ infof(data, " Signature: %s\n", buf);
+ Curl_ssl_push_certinfo(data, numcert, "Signature", buf);
+}
+
+static void dumpcert(struct SessionHandle *data, X509 *x, int numcert)
+{
+ BIO *bio_out = BIO_new(BIO_s_mem());
+ BUF_MEM *biomem;
+
+ /* this outputs the cert in this 64 column wide style with newlines and
+ -----BEGIN CERTIFICATE----- texts and more */
+ PEM_write_bio_X509(bio_out, x);
+
+ BIO_get_mem_ptr(bio_out, &biomem);
+
+ infof(data, "%s\n", biomem->data);
+
+ Curl_ssl_push_certinfo_len(data, numcert,
+ "Cert", biomem->data, biomem->length);
+
+ BIO_free(bio_out);
+
+}
+
+/*
+ * This size was previously 512 which has been reported "too small" without
+ * any specifics, so it was enlarged to allow more data to get shown uncut.
+ * The "perfect" size is yet to figure out.
+ */
+#define CERTBUFFERSIZE 8192
+
+static CURLcode get_cert_chain(struct connectdata *conn,
+ struct ssl_connect_data *connssl)
+
+{
+ STACK_OF(X509) *sk;
+ int i;
+ char *bufp;
+ struct SessionHandle *data = conn->data;
+ int numcerts;
+
+ bufp = malloc(CERTBUFFERSIZE);
+ if(!bufp)
+ return CURLE_OUT_OF_MEMORY;
+
+ sk = SSL_get_peer_cert_chain(connssl->handle);
+ if(!sk) {
+ free(bufp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ numcerts = sk_X509_num(sk);
+ if(Curl_ssl_init_certinfo(data, numcerts)) {
+ free(bufp);
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ infof(data, "--- Certificate chain\n");
+ for(i=0; i<numcerts; i++) {
+ long value;
+ ASN1_INTEGER *num;
+ ASN1_TIME *certdate;
+
+ /* get the certs in "importance order" */
+#if 0
+ X509 *x = sk_X509_value(sk, numcerts - i - 1);
+#else
+ X509 *x = sk_X509_value(sk, i);
+#endif
+
+ X509_CINF *cinf;
+ EVP_PKEY *pubkey=NULL;
+ int j;
+ char *ptr;
+
+ (void)x509_name_oneline(X509_get_subject_name(x), bufp, CERTBUFFERSIZE);
+ infof(data, "%2d Subject: %s\n", i, bufp);
+ Curl_ssl_push_certinfo(data, i, "Subject", bufp);
+
+ (void)x509_name_oneline(X509_get_issuer_name(x), bufp, CERTBUFFERSIZE);
+ infof(data, " Issuer: %s\n", bufp);
+ Curl_ssl_push_certinfo(data, i, "Issuer", bufp);
+
+ value = X509_get_version(x);
+ infof(data, " Version: %lu (0x%lx)\n", value+1, value);
+ snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
+ Curl_ssl_push_certinfo(data, i, "Version", bufp); /* hex */
+
+ num=X509_get_serialNumber(x);
+ if(num->length <= 4) {
+ value = ASN1_INTEGER_get(num);
+ infof(data," Serial Number: %ld (0x%lx)\n", value, value);
+ snprintf(bufp, CERTBUFFERSIZE, "%lx", value);
+ }
+ else {
+ int left = CERTBUFFERSIZE;
+
+ ptr = bufp;
+ *ptr++ = 0;
+ if(num->type == V_ASN1_NEG_INTEGER)
+ *ptr++='-';
+
+ for(j=0; (j<num->length) && (left>=4); j++) {
+ /* TODO: length restrictions */
+ snprintf(ptr, 3, "%02x%c",num->data[j],
+ ((j+1 == num->length)?'\n':':'));
+ ptr += 3;
+ left-=4;
+ }
+ if(num->length)
+ infof(data," Serial Number: %s\n", bufp);
+ else
+ bufp[0]=0;
+ }
+ if(bufp[0])
+ Curl_ssl_push_certinfo(data, i, "Serial Number", bufp); /* hex */
+
+ cinf = x->cert_info;
+
+ j = asn1_object_dump(cinf->signature->algorithm, bufp, CERTBUFFERSIZE);
+ if(!j) {
+ infof(data, " Signature Algorithm: %s\n", bufp);
+ Curl_ssl_push_certinfo(data, i, "Signature Algorithm", bufp);
+ }
+
+ certdate = X509_get_notBefore(x);
+ asn1_output(certdate, bufp, CERTBUFFERSIZE);
+ infof(data, " Start date: %s\n", bufp);
+ Curl_ssl_push_certinfo(data, i, "Start date", bufp);
+
+ certdate = X509_get_notAfter(x);
+ asn1_output(certdate, bufp, CERTBUFFERSIZE);
+ infof(data, " Expire date: %s\n", bufp);
+ Curl_ssl_push_certinfo(data, i, "Expire date", bufp);
+
+ j = asn1_object_dump(cinf->key->algor->algorithm, bufp, CERTBUFFERSIZE);
+ if(!j) {
+ infof(data, " Public Key Algorithm: %s\n", bufp);
+ Curl_ssl_push_certinfo(data, i, "Public Key Algorithm", bufp);
+ }
+
+ pubkey = X509_get_pubkey(x);
+ if(!pubkey)
+ infof(data, " Unable to load public key\n");
+ else {
+ switch(pubkey->type) {
+ case EVP_PKEY_RSA:
+ infof(data, " RSA Public Key (%d bits)\n",
+ BN_num_bits(pubkey->pkey.rsa->n));
+ snprintf(bufp, CERTBUFFERSIZE, "%d", BN_num_bits(pubkey->pkey.rsa->n));
+ Curl_ssl_push_certinfo(data, i, "RSA Public Key", bufp);
+
+ print_pubkey_BN(rsa, n, i);
+ print_pubkey_BN(rsa, e, i);
+ print_pubkey_BN(rsa, d, i);
+ print_pubkey_BN(rsa, p, i);
+ print_pubkey_BN(rsa, q, i);
+ print_pubkey_BN(rsa, dmp1, i);
+ print_pubkey_BN(rsa, dmq1, i);
+ print_pubkey_BN(rsa, iqmp, i);
+ break;
+ case EVP_PKEY_DSA:
+ print_pubkey_BN(dsa, p, i);
+ print_pubkey_BN(dsa, q, i);
+ print_pubkey_BN(dsa, g, i);
+ print_pubkey_BN(dsa, priv_key, i);
+ print_pubkey_BN(dsa, pub_key, i);
+ break;
+ case EVP_PKEY_DH:
+ print_pubkey_BN(dh, p, i);
+ print_pubkey_BN(dh, g, i);
+ print_pubkey_BN(dh, priv_key, i);
+ print_pubkey_BN(dh, pub_key, i);
+ break;
+#if 0
+ case EVP_PKEY_EC: /* symbol not present in OpenSSL 0.9.6 */
+ /* left TODO */
+ break;
+#endif
+ }
+ EVP_PKEY_free(pubkey);
+ }
+
+ X509V3_ext(data, i, cinf->extensions);
+
+ X509_signature(data, i, x->signature);
+
+ dumpcert(data, x, i);
+ }
+
+ free(bufp);
+
+ return CURLE_OK;
+}
+
+/*
+ * Get the server cert, verify it and show it etc, only call failf() if the
+ * 'strict' argument is TRUE as otherwise all this is for informational
+ * purposes only!
+ *
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack.
+ */
+static CURLcode servercert(struct connectdata *conn,
+ struct ssl_connect_data *connssl,
+ bool strict)
+{
+ CURLcode retcode = CURLE_OK;
+ int rc;
+ long lerr;
+ ASN1_TIME *certdate;
+ struct SessionHandle *data = conn->data;
+ X509 *issuer;
+ FILE *fp;
+ char *buffer = data->state.buffer;
+
+ if(data->set.ssl.certinfo)
+ /* we've been asked to gather certificate info! */
+ (void)get_cert_chain(conn, connssl);
+
+ data->set.ssl.certverifyresult = !X509_V_OK;
+
+ connssl->server_cert = SSL_get_peer_certificate(connssl->handle);
+ if(!connssl->server_cert) {
+ if(strict)
+ failf(data, "SSL: couldn't get peer certificate!");
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+ infof (data, "Server certificate:\n");
+
+ rc = x509_name_oneline(X509_get_subject_name(connssl->server_cert),
+ buffer, BUFSIZE);
+ infof(data, "\t subject: %s\n", rc?"[NONE]":buffer);
+
+ certdate = X509_get_notBefore(connssl->server_cert);
+ asn1_output(certdate, buffer, BUFSIZE);
+ infof(data, "\t start date: %s\n", buffer);
+
+ certdate = X509_get_notAfter(connssl->server_cert);
+ asn1_output(certdate, buffer, BUFSIZE);
+ infof(data, "\t expire date: %s\n", buffer);
+
+ if(data->set.ssl.verifyhost) {
+ retcode = verifyhost(conn, connssl->server_cert);
+ if(retcode) {
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return retcode;
+ }
+ }
+
+ rc = x509_name_oneline(X509_get_issuer_name(connssl->server_cert),
+ buffer, BUFSIZE);
+ if(rc) {
+ if(strict)
+ failf(data, "SSL: couldn't get X509-issuer name!");
+ retcode = CURLE_SSL_CONNECT_ERROR;
+ }
+ else {
+ infof(data, "\t issuer: %s\n", buffer);
+
+ /* We could do all sorts of certificate verification stuff here before
+ deallocating the certificate. */
+
+ /* e.g. match issuer name with provided issuer certificate */
+ if(data->set.str[STRING_SSL_ISSUERCERT]) {
+ fp=fopen(data->set.str[STRING_SSL_ISSUERCERT],"r");
+ if(!fp) {
+ if(strict)
+ failf(data, "SSL: Unable to open issuer cert (%s)",
+ data->set.str[STRING_SSL_ISSUERCERT]);
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+ issuer = PEM_read_X509(fp,NULL,ZERO_NULL,NULL);
+ if(!issuer) {
+ if(strict)
+ failf(data, "SSL: Unable to read issuer cert (%s)",
+ data->set.str[STRING_SSL_ISSUERCERT]);
+ X509_free(connssl->server_cert);
+ X509_free(issuer);
+ fclose(fp);
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+ fclose(fp);
+ if(X509_check_issued(issuer,connssl->server_cert) != X509_V_OK) {
+ if(strict)
+ failf(data, "SSL: Certificate issuer check failed (%s)",
+ data->set.str[STRING_SSL_ISSUERCERT]);
+ X509_free(connssl->server_cert);
+ X509_free(issuer);
+ connssl->server_cert = NULL;
+ return CURLE_SSL_ISSUER_ERROR;
+ }
+ infof(data, "\t SSL certificate issuer check ok (%s)\n",
+ data->set.str[STRING_SSL_ISSUERCERT]);
+ X509_free(issuer);
+ }
+
+ lerr = data->set.ssl.certverifyresult=
+ SSL_get_verify_result(connssl->handle);
+ if(data->set.ssl.certverifyresult != X509_V_OK) {
+ if(data->set.ssl.verifypeer) {
+ /* We probably never reach this, because SSL_connect() will fail
+ and we return earlier if verifypeer is set? */
+ if(strict)
+ failf(data, "SSL certificate verify result: %s (%ld)",
+ X509_verify_cert_error_string(lerr), lerr);
+ retcode = CURLE_PEER_FAILED_VERIFICATION;
+ }
+ else
+ infof(data, "\t SSL certificate verify result: %s (%ld),"
+ " continuing anyway.\n",
+ X509_verify_cert_error_string(lerr), lerr);
+ }
+ else
+ infof(data, "\t SSL certificate verify ok.\n");
+ }
+
+ X509_free(connssl->server_cert);
+ connssl->server_cert = NULL;
+ connssl->connecting_state = ssl_connect_done;
+
+ return retcode;
+}
+
+
+static CURLcode
+ossl_connect_step3(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode = CURLE_OK;
+ void *old_ssl_sessionid=NULL;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ int incache;
+ SSL_SESSION *our_ssl_sessionid;
+
+ DEBUGASSERT(ssl_connect_3 == connssl->connecting_state);
+
+#ifdef HAVE_SSL_GET1_SESSION
+ our_ssl_sessionid = SSL_get1_session(connssl->handle);
+
+ /* SSL_get1_session() will increment the reference
+ count and the session will stay in memory until explicitly freed with
+ SSL_SESSION_free(3), regardless of its state.
+ This function was introduced in openssl 0.9.5a. */
+#else
+ our_ssl_sessionid = SSL_get_session(connssl->handle);
+
+ /* if SSL_get1_session() is unavailable, use SSL_get_session().
+ This is an inferior option because the session can be flushed
+ at any time by openssl. It is included only so curl compiles
+ under versions of openssl < 0.9.5a.
+
+ WARNING: How curl behaves if it's session is flushed is
+ untested.
+ */
+#endif
+
+ incache = !(Curl_ssl_getsessionid(conn, &old_ssl_sessionid, NULL));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+ Curl_ssl_delsessionid(conn, old_ssl_sessionid);
+ incache = FALSE;
+ }
+ }
+ if(!incache) {
+ retcode = Curl_ssl_addsessionid(conn, our_ssl_sessionid,
+ 0 /* unknown size */);
+ if(retcode) {
+ failf(data, "failed to store ssl session");
+ return retcode;
+ }
+ }
+#ifdef HAVE_SSL_GET1_SESSION
+ else {
+ /* Session was incache, so refcount already incremented earlier.
+ * Avoid further increments with each SSL_get1_session() call.
+ * This does not free the session as refcount remains > 0
+ */
+ SSL_SESSION_free(our_ssl_sessionid);
+ }
+#endif
+
+ /*
+ * We check certificates to authenticate the server; otherwise we risk
+ * man-in-the-middle attack; NEVERTHELESS, if we're told explicitly not to
+ * verify the peer ignore faults and failures from the server cert
+ * operations.
+ */
+
+ if(!data->set.ssl.verifypeer && !data->set.ssl.verifyhost)
+ (void)servercert(conn, connssl, FALSE);
+ else
+ retcode = servercert(conn, connssl, TRUE);
+
+ if(CURLE_OK == retcode)
+ connssl->connecting_state = ssl_connect_done;
+ return retcode;
+}
+
+static Curl_recv ossl_recv;
+static Curl_send ossl_send;
+
+static CURLcode
+ossl_connect_common(struct connectdata *conn,
+ int sockindex,
+ bool nonblocking,
+ bool *done)
+{
+ CURLcode retcode;
+ struct SessionHandle *data = conn->data;
+ struct ssl_connect_data *connssl = &conn->ssl[sockindex];
+ curl_socket_t sockfd = conn->sock[sockindex];
+ long timeout_ms;
+ int what;
+
+ /* check if the connection has already been established */
+ if(ssl_connection_complete == connssl->state) {
+ *done = TRUE;
+ return CURLE_OK;
+ }
+
+ if(ssl_connect_1==connssl->connecting_state) {
+ /* Find out how much more time we're allowed */
+ 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ retcode = ossl_connect_step1(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ while(ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state) {
+
+ /* 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");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ /* if ssl is expecting something, check if it's available. */
+ if(connssl->connecting_state == ssl_connect_2_reading
+ || connssl->connecting_state == ssl_connect_2_writing) {
+
+ curl_socket_t writefd = ssl_connect_2_writing==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+ curl_socket_t readfd = ssl_connect_2_reading==
+ connssl->connecting_state?sockfd:CURL_SOCKET_BAD;
+
+ what = Curl_socket_ready(readfd, writefd, nonblocking?0:timeout_ms);
+ if(what < 0) {
+ /* fatal error */
+ failf(data, "select/poll on SSL socket, errno: %d", SOCKERRNO);
+ return CURLE_SSL_CONNECT_ERROR;
+ }
+ else if(0 == what) {
+ if(nonblocking) {
+ *done = FALSE;
+ return CURLE_OK;
+ }
+ else {
+ /* timeout */
+ failf(data, "SSL connection timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ /* socket is readable or writable */
+ }
+
+ /* Run transaction, and return to the caller if it failed or if this
+ * connection is done nonblocking and this loop would execute again. This
+ * permits the owner of a multi handle to abort a connection attempt
+ * before step2 has completed while ensuring that a client using select()
+ * or epoll() will always have a valid fdset to wait on.
+ */
+ retcode = ossl_connect_step2(conn, sockindex);
+ if(retcode || (nonblocking &&
+ (ssl_connect_2 == connssl->connecting_state ||
+ ssl_connect_2_reading == connssl->connecting_state ||
+ ssl_connect_2_writing == connssl->connecting_state)))
+ return retcode;
+
+ } /* repeat step2 until all transactions are done. */
+
+
+ if(ssl_connect_3==connssl->connecting_state) {
+ retcode = ossl_connect_step3(conn, sockindex);
+ if(retcode)
+ return retcode;
+ }
+
+ if(ssl_connect_done==connssl->connecting_state) {
+ connssl->state = ssl_connection_complete;
+ conn->recv[sockindex] = ossl_recv;
+ conn->send[sockindex] = ossl_send;
+ *done = TRUE;
+ }
+ else
+ *done = FALSE;
+
+ /* Reset our connect state machine */
+ connssl->connecting_state = ssl_connect_1;
+
+ return CURLE_OK;
+}
+
+CURLcode
+Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done)
+{
+ return ossl_connect_common(conn, sockindex, TRUE, done);
+}
+
+CURLcode
+Curl_ossl_connect(struct connectdata *conn,
+ int sockindex)
+{
+ CURLcode retcode;
+ bool done = FALSE;
+
+ retcode = ossl_connect_common(conn, sockindex, FALSE, &done);
+ if(retcode)
+ return retcode;
+
+ DEBUGASSERT(done);
+
+ return CURLE_OK;
+}
+
+bool Curl_ossl_data_pending(const struct connectdata *conn,
+ int connindex)
+{
+ if(conn->ssl[connindex].handle)
+ /* SSL is in use */
+ return (0 != SSL_pending(conn->ssl[connindex].handle)) ? TRUE : FALSE;
+ else
+ return FALSE;
+}
+
+static ssize_t ossl_send(struct connectdata *conn,
+ int sockindex,
+ const void *mem,
+ size_t len,
+ CURLcode *curlcode)
+{
+ /* SSL_write() is said to return 'int' while write() and send() returns
+ 'size_t' */
+ int err;
+ char error_buffer[120]; /* OpenSSL documents that this must be at least 120
+ bytes long. */
+ unsigned long sslerror;
+ int memlen;
+ int rc;
+
+ ERR_clear_error();
+
+ memlen = (len > (size_t)INT_MAX) ? INT_MAX : (int)len;
+ rc = SSL_write(conn->ssl[sockindex].handle, mem, memlen);
+
+ if(rc <= 0) {
+ err = SSL_get_error(conn->ssl[sockindex].handle, rc);
+
+ switch(err) {
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* The operation did not complete; the same TLS/SSL I/O function
+ should be called again later. This is basically an EWOULDBLOCK
+ equivalent. */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ case SSL_ERROR_SYSCALL:
+ failf(conn->data, "SSL_write() returned SYSCALL, errno = %d",
+ SOCKERRNO);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ case SSL_ERROR_SSL:
+ /* A failure in the SSL library occurred, usually a protocol error.
+ The OpenSSL error queue contains more information on the error. */
+ sslerror = ERR_get_error();
+ failf(conn->data, "SSL_write() error: %s",
+ ERR_error_string(sslerror, error_buffer));
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ /* a true error */
+ failf(conn->data, "SSL_write() return error %d", err);
+ *curlcode = CURLE_SEND_ERROR;
+ return -1;
+ }
+ return (ssize_t)rc; /* number of bytes */
+}
+
+static ssize_t ossl_recv(struct connectdata *conn, /* connection data */
+ int num, /* socketindex */
+ char *buf, /* store read data here */
+ size_t buffersize, /* max amount to read */
+ CURLcode *curlcode)
+{
+ char error_buffer[120]; /* OpenSSL documents that this must be at
+ least 120 bytes long. */
+ unsigned long sslerror;
+ ssize_t nread;
+ int buffsize;
+
+ ERR_clear_error();
+
+ buffsize = (buffersize > (size_t)INT_MAX) ? INT_MAX : (int)buffersize;
+ nread = (ssize_t)SSL_read(conn->ssl[num].handle, buf, buffsize);
+ if(nread <= 0) {
+ /* failed SSL_read */
+ int err = SSL_get_error(conn->ssl[num].handle, (int)nread);
+
+ switch(err) {
+ case SSL_ERROR_NONE: /* this is not an error */
+ case SSL_ERROR_ZERO_RETURN: /* no more data */
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ /* there's data pending, re-invoke SSL_read() */
+ *curlcode = CURLE_AGAIN;
+ return -1;
+ default:
+ /* openssl/ssl.h for SSL_ERROR_SYSCALL says "look at error stack/return
+ value/errno" */
+ /* http://www.openssl.org/docs/crypto/ERR_get_error.html */
+ sslerror = ERR_get_error();
+ if((nread < 0) || sslerror) {
+ /* If the return code was negative or there actually is an error in the
+ queue */
+ failf(conn->data, "SSL read: %s, errno %d",
+ ERR_error_string(sslerror, error_buffer),
+ SOCKERRNO);
+ *curlcode = CURLE_RECV_ERROR;
+ return -1;
+ }
+ }
+ }
+ return nread;
+}
+
+size_t Curl_ossl_version(char *buffer, size_t size)
+{
+#ifdef YASSL_VERSION
+ /* yassl provides an OpenSSL API compatibility layer so it looks identical
+ to OpenSSL in all other aspects */
+ return snprintf(buffer, size, "yassl/%s", YASSL_VERSION);
+#else /* YASSL_VERSION */
+
+#if(SSLEAY_VERSION_NUMBER >= 0x905000)
+ {
+ char sub[2];
+ unsigned long ssleay_value;
+ sub[1]='\0';
+ ssleay_value=SSLeay();
+ if(ssleay_value < 0x906000) {
+ ssleay_value=SSLEAY_VERSION_NUMBER;
+ sub[0]='\0';
+ }
+ else {
+ if(ssleay_value&0xff0) {
+ sub[0]=(char)(((ssleay_value>>4)&0xff) + 'a' -1);
+ }
+ else
+ sub[0]='\0';
+ }
+
+ return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx%s",
+ (ssleay_value>>28)&0xf,
+ (ssleay_value>>20)&0xff,
+ (ssleay_value>>12)&0xff,
+ sub);
+ }
+
+#else /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+
+#if(SSLEAY_VERSION_NUMBER >= 0x900000)
+ return snprintf(buffer, size, "OpenSSL/%lx.%lx.%lx",
+ (SSLEAY_VERSION_NUMBER>>28)&0xff,
+ (SSLEAY_VERSION_NUMBER>>20)&0xff,
+ (SSLEAY_VERSION_NUMBER>>12)&0xf);
+
+#else /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
+ {
+ char sub[2];
+ sub[1]='\0';
+ if(SSLEAY_VERSION_NUMBER&0x0f) {
+ sub[0]=(SSLEAY_VERSION_NUMBER&0x0f) + 'a' -1;
+ }
+ else
+ sub[0]='\0';
+
+ return snprintf(buffer, size, "SSL/%x.%x.%x%s",
+ (SSLEAY_VERSION_NUMBER>>12)&0xff,
+ (SSLEAY_VERSION_NUMBER>>8)&0xf,
+ (SSLEAY_VERSION_NUMBER>>4)&0xf, sub);
+ }
+#endif /* (SSLEAY_VERSION_NUMBER >= 0x900000) */
+#endif /* SSLEAY_VERSION_NUMBER is less than 0.9.5 */
+
+#endif /* YASSL_VERSION */
+}
+
+void Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
+ size_t length)
+{
+ Curl_ossl_seed(data); /* Initiate the seed if not already done */
+ RAND_bytes(entropy, curlx_uztosi(length));
+}
+
+void Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused)
+{
+ MD5_CTX MD5pw;
+ (void)unused;
+ MD5_Init(&MD5pw);
+ MD5_Update(&MD5pw, tmp, tmplen);
+ MD5_Final(md5sum, &MD5pw);
+}
+#endif /* USE_SSLEAY */
diff --git a/libs/libcurl/src/ssluse.h b/libs/libcurl/src/ssluse.h
new file mode 100644
index 0000000000..d6efcb2717
--- /dev/null
+++ b/libs/libcurl/src/ssluse.h
@@ -0,0 +1,99 @@
+#ifndef HEADER_CURL_SSLUSE_H
+#define HEADER_CURL_SSLUSE_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"
+
+#ifdef USE_SSLEAY
+/*
+ * This header should only be needed to get included by sslgen.c and ssluse.c
+ */
+
+#include "urldata.h"
+
+CURLcode Curl_ossl_connect(struct connectdata *conn, int sockindex);
+CURLcode Curl_ossl_connect_nonblocking(struct connectdata *conn,
+ int sockindex,
+ bool *done);
+
+/* close a SSL connection */
+void Curl_ossl_close(struct connectdata *conn, int sockindex);
+
+/* tell OpenSSL to close down all open information regarding connections (and
+ thus session ID caching etc) */
+int Curl_ossl_close_all(struct SessionHandle *data);
+
+/* Sets an OpenSSL engine */
+CURLcode Curl_ossl_set_engine(struct SessionHandle *data, const char *engine);
+
+/* function provided for the generic SSL-layer, called when a session id
+ should be freed */
+void Curl_ossl_session_free(void *ptr);
+
+/* Sets engine as default for all SSL operations */
+CURLcode Curl_ossl_set_engine_default(struct SessionHandle *data);
+
+/* Build list of OpenSSL engines */
+struct curl_slist *Curl_ossl_engines_list(struct SessionHandle *data);
+
+int Curl_ossl_init(void);
+void Curl_ossl_cleanup(void);
+
+size_t Curl_ossl_version(char *buffer, size_t size);
+int Curl_ossl_check_cxn(struct connectdata *cxn);
+int Curl_ossl_seed(struct SessionHandle *data);
+
+int Curl_ossl_shutdown(struct connectdata *conn, int sockindex);
+bool Curl_ossl_data_pending(const struct connectdata *conn,
+ int connindex);
+void Curl_ossl_random(struct SessionHandle *data, unsigned char *entropy,
+ size_t length);
+void Curl_ossl_md5sum(unsigned char *tmp, /* input */
+ size_t tmplen,
+ unsigned char *md5sum /* output */,
+ size_t unused);
+
+/* this backend provides these functions: */
+#define have_curlssl_random 1
+#define have_curlssl_md5sum 1
+
+/* API setup for OpenSSL */
+#define curlssl_init Curl_ossl_init
+#define curlssl_cleanup Curl_ossl_cleanup
+#define curlssl_connect Curl_ossl_connect
+#define curlssl_connect_nonblocking Curl_ossl_connect_nonblocking
+#define curlssl_session_free(x) Curl_ossl_session_free(x)
+#define curlssl_close_all Curl_ossl_close_all
+#define curlssl_close Curl_ossl_close
+#define curlssl_shutdown(x,y) Curl_ossl_shutdown(x,y)
+#define curlssl_set_engine(x,y) Curl_ossl_set_engine(x,y)
+#define curlssl_set_engine_default(x) Curl_ossl_set_engine_default(x)
+#define curlssl_engines_list(x) Curl_ossl_engines_list(x)
+#define curlssl_version Curl_ossl_version
+#define curlssl_check_cxn Curl_ossl_check_cxn
+#define curlssl_data_pending(x,y) Curl_ossl_data_pending(x,y)
+#define curlssl_random(x,y,z) Curl_ossl_random(x,y,z)
+#define curlssl_md5sum(a,b,c,d) Curl_ossl_md5sum(a,b,c,d)
+
+#endif /* USE_SSLEAY */
+#endif /* HEADER_CURL_SSLUSE_H */
diff --git a/libs/libcurl/src/stdafx.cxx b/libs/libcurl/src/stdafx.cxx
new file mode 100644
index 0000000000..0fb604da7c
--- /dev/null
+++ b/libs/libcurl/src/stdafx.cxx
@@ -0,0 +1,2 @@
+
+#include "stdafx.h" \ No newline at end of file
diff --git a/libs/libcurl/src/stdafx.h b/libs/libcurl/src/stdafx.h
new file mode 100644
index 0000000000..d78b7834c8
--- /dev/null
+++ b/libs/libcurl/src/stdafx.h
@@ -0,0 +1,2 @@
+
+// just a stub \ No newline at end of file
diff --git a/libs/libcurl/src/strdup.c b/libs/libcurl/src/strdup.c
new file mode 100644
index 0000000000..3b776b1845
--- /dev/null
+++ b/libs/libcurl/src/strdup.c
@@ -0,0 +1,52 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 file is 'mem-include-scan' clean. See test 1132.
+ */
+#include "curl_setup.h"
+
+#include "strdup.h"
+
+#ifndef HAVE_STRDUP
+char *curlx_strdup(const char *str)
+{
+ size_t len;
+ char *newstr;
+
+ if(!str)
+ return (char *)NULL;
+
+ len = strlen(str);
+
+ if(len >= ((size_t)-1) / sizeof(char))
+ return (char *)NULL;
+
+ newstr = malloc((len+1)*sizeof(char));
+ if(!newstr)
+ return (char *)NULL;
+
+ memcpy(newstr,str,(len+1)*sizeof(char));
+
+ return newstr;
+
+}
+#endif
diff --git a/libs/libcurl/src/strdup.h b/libs/libcurl/src/strdup.h
new file mode 100644
index 0000000000..49af9117ee
--- /dev/null
+++ b/libs/libcurl/src/strdup.h
@@ -0,0 +1,30 @@
+#ifndef HEADER_CURL_STRDUP_H
+#define HEADER_CURL_STRDUP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+#ifndef HAVE_STRDUP
+extern char *curlx_strdup(const char *str);
+#endif
+
+#endif /* HEADER_CURL_STRDUP_H */
diff --git a/libs/libcurl/src/strequal.c b/libs/libcurl/src/strequal.c
new file mode 100644
index 0000000000..5f2f508e21
--- /dev/null
+++ b/libs/libcurl/src/strequal.c
@@ -0,0 +1,79 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_STRINGS_H
+#include <strings.h>
+#endif
+
+#include "strequal.h"
+
+/*
+ * @unittest: 1301
+ */
+int curl_strequal(const char *first, const char *second)
+{
+#if defined(HAVE_STRCASECMP)
+ return !(strcasecmp)(first, second);
+#elif defined(HAVE_STRCMPI)
+ return !(strcmpi)(first, second);
+#elif defined(HAVE_STRICMP)
+ return !(stricmp)(first, second);
+#else
+ while(*first && *second) {
+ if(toupper(*first) != toupper(*second)) {
+ break;
+ }
+ first++;
+ second++;
+ }
+ return toupper(*first) == toupper(*second);
+#endif
+}
+
+/*
+ * @unittest: 1301
+ */
+int curl_strnequal(const char *first, const char *second, size_t max)
+{
+#if defined(HAVE_STRNCASECMP)
+ return !strncasecmp(first, second, max);
+#elif defined(HAVE_STRNCMPI)
+ return !strncmpi(first, second, max);
+#elif defined(HAVE_STRNICMP)
+ return !strnicmp(first, second, max);
+#else
+ while(*first && *second && max) {
+ if(toupper(*first) != toupper(*second)) {
+ break;
+ }
+ max--;
+ first++;
+ second++;
+ }
+ if(0 == max)
+ return 1; /* they are equal this far */
+
+ return toupper(*first) == toupper(*second);
+#endif
+}
diff --git a/libs/libcurl/src/strequal.h b/libs/libcurl/src/strequal.h
new file mode 100644
index 0000000000..117a305b76
--- /dev/null
+++ b/libs/libcurl/src/strequal.h
@@ -0,0 +1,31 @@
+#ifndef HEADER_CURL_STREQUAL_H
+#define HEADER_CURL_STREQUAL_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/curl.h>
+
+#define strequal(a,b) curl_strequal(a,b)
+#define strnequal(a,b,c) curl_strnequal(a,b,c)
+
+#endif /* HEADER_CURL_STREQUAL_H */
+
diff --git a/libs/libcurl/src/strerror.c b/libs/libcurl/src/strerror.c
new file mode 100644
index 0000000000..9e8c83f726
--- /dev/null
+++ b/libs/libcurl/src/strerror.c
@@ -0,0 +1,1125 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2004 - 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 HAVE_STRERROR_R
+# if (!defined(HAVE_POSIX_STRERROR_R) && \
+ !defined(HAVE_GLIBC_STRERROR_R) && \
+ !defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_GLIBC_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)) || \
+ (defined(HAVE_POSIX_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R))
+# error "strerror_r MUST be either POSIX, glibc or vxworks-style"
+# endif
+#endif
+
+#include <curl/curl.h>
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#endif
+
+#include "strerror.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"
+
+const char *
+curl_easy_strerror(CURLcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch (error) {
+ case CURLE_OK:
+ return "No error";
+
+ case CURLE_UNSUPPORTED_PROTOCOL:
+ return "Unsupported protocol";
+
+ case CURLE_FAILED_INIT:
+ return "Failed initialization";
+
+ case CURLE_URL_MALFORMAT:
+ return "URL using bad/illegal format or missing URL";
+
+ case CURLE_NOT_BUILT_IN:
+ return "A requested feature, protocol or option was not found built-in in"
+ " this libcurl due to a build-time decision.";
+
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ return "Couldn't resolve proxy name";
+
+ case CURLE_COULDNT_RESOLVE_HOST:
+ return "Couldn't resolve host name";
+
+ case CURLE_COULDNT_CONNECT:
+ return "Couldn't connect to server";
+
+ case CURLE_FTP_WEIRD_SERVER_REPLY:
+ return "FTP: weird server reply";
+
+ case CURLE_REMOTE_ACCESS_DENIED:
+ return "Access denied to remote resource";
+
+ case CURLE_FTP_ACCEPT_FAILED:
+ return "FTP: The server failed to connect to data port";
+
+ case CURLE_FTP_ACCEPT_TIMEOUT:
+ return "FTP: Accepting server connect has timed out";
+
+ case CURLE_FTP_PRET_FAILED:
+ return "FTP: The server did not accept the PRET command.";
+
+ case CURLE_FTP_WEIRD_PASS_REPLY:
+ return "FTP: unknown PASS reply";
+
+ case CURLE_FTP_WEIRD_PASV_REPLY:
+ return "FTP: unknown PASV reply";
+
+ case CURLE_FTP_WEIRD_227_FORMAT:
+ return "FTP: unknown 227 response format";
+
+ case CURLE_FTP_CANT_GET_HOST:
+ return "FTP: can't figure out the host in the PASV response";
+
+ case CURLE_FTP_COULDNT_SET_TYPE:
+ return "FTP: couldn't set file type";
+
+ case CURLE_PARTIAL_FILE:
+ return "Transferred a partial file";
+
+ case CURLE_FTP_COULDNT_RETR_FILE:
+ return "FTP: couldn't retrieve (RETR failed) the specified file";
+
+ case CURLE_QUOTE_ERROR:
+ return "Quote command returned error";
+
+ case CURLE_HTTP_RETURNED_ERROR:
+ return "HTTP response code said error";
+
+ case CURLE_WRITE_ERROR:
+ return "Failed writing received data to disk/application";
+
+ case CURLE_UPLOAD_FAILED:
+ return "Upload failed (at start/before it took off)";
+
+ case CURLE_READ_ERROR:
+ return "Failed to open/read local data from file/application";
+
+ case CURLE_OUT_OF_MEMORY:
+ return "Out of memory";
+
+ case CURLE_OPERATION_TIMEDOUT:
+ return "Timeout was reached";
+
+ case CURLE_FTP_PORT_FAILED:
+ return "FTP: command PORT failed";
+
+ case CURLE_FTP_COULDNT_USE_REST:
+ return "FTP: command REST failed";
+
+ case CURLE_RANGE_ERROR:
+ return "Requested range was not delivered by the server";
+
+ case CURLE_HTTP_POST_ERROR:
+ return "Internal problem setting up the POST";
+
+ case CURLE_SSL_CONNECT_ERROR:
+ return "SSL connect error";
+
+ case CURLE_BAD_DOWNLOAD_RESUME:
+ return "Couldn't resume download";
+
+ case CURLE_FILE_COULDNT_READ_FILE:
+ return "Couldn't read a file:// file";
+
+ case CURLE_LDAP_CANNOT_BIND:
+ return "LDAP: cannot bind";
+
+ case CURLE_LDAP_SEARCH_FAILED:
+ return "LDAP: search failed";
+
+ case CURLE_FUNCTION_NOT_FOUND:
+ return "A required function in the library was not found";
+
+ case CURLE_ABORTED_BY_CALLBACK:
+ return "Operation was aborted by an application callback";
+
+ case CURLE_BAD_FUNCTION_ARGUMENT:
+ return "A libcurl function was given a bad argument";
+
+ case CURLE_INTERFACE_FAILED:
+ return "Failed binding local connection end";
+
+ case CURLE_TOO_MANY_REDIRECTS :
+ return "Number of redirects hit maximum amount";
+
+ case CURLE_UNKNOWN_OPTION:
+ return "An unknown option was passed in to libcurl";
+
+ case CURLE_TELNET_OPTION_SYNTAX :
+ return "Malformed telnet option";
+
+ case CURLE_PEER_FAILED_VERIFICATION:
+ return "SSL peer certificate or SSH remote key was not OK";
+
+ case CURLE_GOT_NOTHING:
+ return "Server returned nothing (no headers, no data)";
+
+ case CURLE_SSL_ENGINE_NOTFOUND:
+ return "SSL crypto engine not found";
+
+ case CURLE_SSL_ENGINE_SETFAILED:
+ return "Can not set SSL crypto engine as default";
+
+ case CURLE_SSL_ENGINE_INITFAILED:
+ return "Failed to initialise SSL crypto engine";
+
+ case CURLE_SEND_ERROR:
+ return "Failed sending data to the peer";
+
+ case CURLE_RECV_ERROR:
+ return "Failure when receiving data from the peer";
+
+ case CURLE_SSL_CERTPROBLEM:
+ return "Problem with the local SSL certificate";
+
+ case CURLE_SSL_CIPHER:
+ return "Couldn't use specified SSL cipher";
+
+ case CURLE_SSL_CACERT:
+ return "Peer certificate cannot be authenticated with given CA "
+ "certificates";
+
+ case CURLE_SSL_CACERT_BADFILE:
+ return "Problem with the SSL CA cert (path? access rights?)";
+
+ case CURLE_BAD_CONTENT_ENCODING:
+ return "Unrecognized or bad HTTP Content or Transfer-Encoding";
+
+ case CURLE_LDAP_INVALID_URL:
+ return "Invalid LDAP URL";
+
+ case CURLE_FILESIZE_EXCEEDED:
+ return "Maximum file size exceeded";
+
+ case CURLE_USE_SSL_FAILED:
+ return "Requested SSL level failed";
+
+ case CURLE_SSL_SHUTDOWN_FAILED:
+ return "Failed to shut down the SSL connection";
+
+ case CURLE_SSL_CRL_BADFILE:
+ return "Failed to load CRL file (path? access rights?, format?)";
+
+ case CURLE_SSL_ISSUER_ERROR:
+ return "Issuer check against peer certificate failed";
+
+ case CURLE_SEND_FAIL_REWIND:
+ return "Send failed since rewinding of the data stream failed";
+
+ case CURLE_LOGIN_DENIED:
+ return "Login denied";
+
+ case CURLE_TFTP_NOTFOUND:
+ return "TFTP: File Not Found";
+
+ case CURLE_TFTP_PERM:
+ return "TFTP: Access Violation";
+
+ case CURLE_REMOTE_DISK_FULL:
+ return "Disk full or allocation exceeded";
+
+ case CURLE_TFTP_ILLEGAL:
+ return "TFTP: Illegal operation";
+
+ case CURLE_TFTP_UNKNOWNID:
+ return "TFTP: Unknown transfer ID";
+
+ case CURLE_REMOTE_FILE_EXISTS:
+ return "Remote file already exists";
+
+ case CURLE_TFTP_NOSUCHUSER:
+ return "TFTP: No such user";
+
+ case CURLE_CONV_FAILED:
+ return "Conversion failed";
+
+ case CURLE_CONV_REQD:
+ return "Caller must register CURLOPT_CONV_ callback options";
+
+ case CURLE_REMOTE_FILE_NOT_FOUND:
+ return "Remote file not found";
+
+ case CURLE_SSH:
+ return "Error in the SSH layer";
+
+ case CURLE_AGAIN:
+ return "Socket not ready for send/recv";
+
+ case CURLE_RTSP_CSEQ_ERROR:
+ return "RTSP CSeq mismatch or invalid CSeq";
+
+ case CURLE_RTSP_SESSION_ERROR:
+ return "RTSP session error";
+
+ case CURLE_FTP_BAD_FILE_LIST:
+ return "Unable to parse FTP file list";
+
+ case CURLE_CHUNK_FAILED:
+ return "Chunk callback failed";
+
+ case CURLE_NO_CONNECTION_AVAILABLE:
+ return "The max connection limit is reached";
+
+ /* error codes not used by current libcurl */
+ case CURLE_OBSOLETE16:
+ case CURLE_OBSOLETE20:
+ case CURLE_OBSOLETE24:
+ case CURLE_OBSOLETE29:
+ case CURLE_OBSOLETE32:
+ case CURLE_OBSOLETE40:
+ case CURLE_OBSOLETE44:
+ case CURLE_OBSOLETE46:
+ case CURLE_OBSOLETE50:
+ case CURLE_OBSOLETE57:
+ case CURL_LAST:
+ break;
+ }
+ /*
+ * By using a switch, gcc -Wall will complain about enum values
+ * which do not appear, helping keep this function up-to-date.
+ * By using gcc -Wall -Werror, you can't forget.
+ *
+ * A table would not have the same benefit. Most compilers will
+ * generate code very similar to a table in any case, so there
+ * is little performance gain from a table. And something is broken
+ * for the user's application, anyways, so does it matter how fast
+ * it _doesn't_ work?
+ *
+ * The line number for the error will be near this comment, which
+ * is why it is here, and not at the start of the switch.
+ */
+ return "Unknown error";
+#else
+ if(error == CURLE_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+const char *
+curl_multi_strerror(CURLMcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch (error) {
+ case CURLM_CALL_MULTI_PERFORM:
+ return "Please call curl_multi_perform() soon";
+
+ case CURLM_OK:
+ return "No error";
+
+ case CURLM_BAD_HANDLE:
+ return "Invalid multi handle";
+
+ case CURLM_BAD_EASY_HANDLE:
+ return "Invalid easy handle";
+
+ case CURLM_OUT_OF_MEMORY:
+ return "Out of memory";
+
+ case CURLM_INTERNAL_ERROR:
+ return "Internal error";
+
+ case CURLM_BAD_SOCKET:
+ return "Invalid socket argument";
+
+ case CURLM_UNKNOWN_OPTION:
+ return "Unknown option";
+
+ case CURLM_ADDED_ALREADY:
+ return "The easy handle is already added to a multi handle";
+
+ case CURLM_LAST:
+ break;
+ }
+
+ return "Unknown error";
+#else
+ if(error == CURLM_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+const char *
+curl_share_strerror(CURLSHcode error)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch (error) {
+ case CURLSHE_OK:
+ return "No error";
+
+ case CURLSHE_BAD_OPTION:
+ return "Unknown share option";
+
+ case CURLSHE_IN_USE:
+ return "Share currently in use";
+
+ case CURLSHE_INVALID:
+ return "Invalid share handle";
+
+ case CURLSHE_NOMEM:
+ return "Out of memory";
+
+ case CURLSHE_NOT_BUILT_IN:
+ return "Feature not enabled in this library";
+
+ case CURLSHE_LAST:
+ break;
+ }
+
+ return "CURLSHcode unknown";
+#else
+ if(error == CURLSHE_OK)
+ return "No error";
+ else
+ return "Error";
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/* This function handles most / all (?) Winsock errors cURL is able to produce.
+ */
+static const char *
+get_winsock_error (int err, char *buf, size_t len)
+{
+ const char *p;
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch (err) {
+ case WSAEINTR:
+ p = "Call interrupted";
+ break;
+ case WSAEBADF:
+ p = "Bad file";
+ break;
+ case WSAEACCES:
+ p = "Bad access";
+ break;
+ case WSAEFAULT:
+ p = "Bad argument";
+ break;
+ case WSAEINVAL:
+ p = "Invalid arguments";
+ break;
+ case WSAEMFILE:
+ p = "Out of file descriptors";
+ break;
+ case WSAEWOULDBLOCK:
+ p = "Call would block";
+ break;
+ case WSAEINPROGRESS:
+ case WSAEALREADY:
+ p = "Blocking call in progress";
+ break;
+ case WSAENOTSOCK:
+ p = "Descriptor is not a socket";
+ break;
+ case WSAEDESTADDRREQ:
+ p = "Need destination address";
+ break;
+ case WSAEMSGSIZE:
+ p = "Bad message size";
+ break;
+ case WSAEPROTOTYPE:
+ p = "Bad protocol";
+ break;
+ case WSAENOPROTOOPT:
+ p = "Protocol option is unsupported";
+ break;
+ case WSAEPROTONOSUPPORT:
+ p = "Protocol is unsupported";
+ break;
+ case WSAESOCKTNOSUPPORT:
+ p = "Socket is unsupported";
+ break;
+ case WSAEOPNOTSUPP:
+ p = "Operation not supported";
+ break;
+ case WSAEAFNOSUPPORT:
+ p = "Address family not supported";
+ break;
+ case WSAEPFNOSUPPORT:
+ p = "Protocol family not supported";
+ break;
+ case WSAEADDRINUSE:
+ p = "Address already in use";
+ break;
+ case WSAEADDRNOTAVAIL:
+ p = "Address not available";
+ break;
+ case WSAENETDOWN:
+ p = "Network down";
+ break;
+ case WSAENETUNREACH:
+ p = "Network unreachable";
+ break;
+ case WSAENETRESET:
+ p = "Network has been reset";
+ break;
+ case WSAECONNABORTED:
+ p = "Connection was aborted";
+ break;
+ case WSAECONNRESET:
+ p = "Connection was reset";
+ break;
+ case WSAENOBUFS:
+ p = "No buffer space";
+ break;
+ case WSAEISCONN:
+ p = "Socket is already connected";
+ break;
+ case WSAENOTCONN:
+ p = "Socket is not connected";
+ break;
+ case WSAESHUTDOWN:
+ p = "Socket has been shut down";
+ break;
+ case WSAETOOMANYREFS:
+ p = "Too many references";
+ break;
+ case WSAETIMEDOUT:
+ p = "Timed out";
+ break;
+ case WSAECONNREFUSED:
+ p = "Connection refused";
+ break;
+ case WSAELOOP:
+ p = "Loop??";
+ break;
+ case WSAENAMETOOLONG:
+ p = "Name too long";
+ break;
+ case WSAEHOSTDOWN:
+ p = "Host down";
+ break;
+ case WSAEHOSTUNREACH:
+ p = "Host unreachable";
+ break;
+ case WSAENOTEMPTY:
+ p = "Not empty";
+ break;
+ case WSAEPROCLIM:
+ p = "Process limit reached";
+ break;
+ case WSAEUSERS:
+ p = "Too many users";
+ break;
+ case WSAEDQUOT:
+ p = "Bad quota";
+ break;
+ case WSAESTALE:
+ p = "Something is stale";
+ break;
+ case WSAEREMOTE:
+ p = "Remote error";
+ break;
+#ifdef WSAEDISCON /* missing in SalfordC! */
+ case WSAEDISCON:
+ p = "Disconnected";
+ break;
+#endif
+ /* Extended Winsock errors */
+ case WSASYSNOTREADY:
+ p = "Winsock library is not ready";
+ break;
+ case WSANOTINITIALISED:
+ p = "Winsock library not initialised";
+ break;
+ case WSAVERNOTSUPPORTED:
+ p = "Winsock version not supported";
+ break;
+
+ /* getXbyY() errors (already handled in herrmsg):
+ * Authoritative Answer: Host not found */
+ case WSAHOST_NOT_FOUND:
+ p = "Host not found";
+ break;
+
+ /* Non-Authoritative: Host not found, or SERVERFAIL */
+ case WSATRY_AGAIN:
+ p = "Host not found, try again";
+ break;
+
+ /* Non recoverable errors, FORMERR, REFUSED, NOTIMP */
+ case WSANO_RECOVERY:
+ p = "Unrecoverable error in call to nameserver";
+ break;
+
+ /* Valid name, no data record of requested type */
+ case WSANO_DATA:
+ p = "No data record of requested type";
+ break;
+
+ default:
+ return NULL;
+ }
+#else
+ if(err == CURLE_OK)
+ return NULL;
+ else
+ p = "error";
+#endif
+ strncpy (buf, p, len);
+ buf [len-1] = '\0';
+ return buf;
+}
+#endif /* USE_WINSOCK */
+
+/*
+ * Our thread-safe and smart strerror() replacement.
+ *
+ * The 'err' argument passed in to this function MUST be a true errno number
+ * as reported on this system. We do no range checking on the number before
+ * we pass it to the "number-to-message" conversion function and there might
+ * be systems that don't do proper range checking in there themselves.
+ *
+ * We don't do range checking (on systems other than Windows) since there is
+ * no good reliable and portable way to do it.
+ */
+const char *Curl_strerror(struct connectdata *conn, int err)
+{
+ char *buf, *p;
+ size_t max;
+ int old_errno = ERRNO;
+
+ DEBUGASSERT(conn);
+ DEBUGASSERT(err >= 0);
+
+ buf = conn->syserr_buf;
+ max = sizeof(conn->syserr_buf)-1;
+ *buf = '\0';
+
+#ifdef USE_WINSOCK
+
+#ifdef _WIN32_WCE
+ {
+ wchar_t wbuf[256];
+ wbuf[0] = L'\0';
+
+ FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ LANG_NEUTRAL, wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL);
+ wcstombs(buf,wbuf,max);
+ }
+#else
+ /* 'sys_nerr' is the maximum errno number, it is not widely portable */
+ if(err >= 0 && err < sys_nerr)
+ strncpy(buf, strerror(err), max);
+ else {
+ if(!get_winsock_error(err, buf, max) &&
+ !FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, NULL, err,
+ LANG_NEUTRAL, buf, (DWORD)max, NULL))
+ snprintf(buf, max, "Unknown error %d (%#x)", err, err);
+ }
+#endif
+
+#else /* not USE_WINSOCK coming up */
+
+#if defined(HAVE_STRERROR_R) && defined(HAVE_POSIX_STRERROR_R)
+ /*
+ * The POSIX-style strerror_r() may set errno to ERANGE if insufficient
+ * storage is supplied via 'strerrbuf' and 'buflen' to hold the generated
+ * message string, or EINVAL if 'errnum' is not a valid error number.
+ */
+ if(0 != strerror_r(err, buf, max)) {
+ if('\0' == buf[0])
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_GLIBC_STRERROR_R)
+ /*
+ * The glibc-style strerror_r() only *might* use the buffer we pass to
+ * the function, but it always returns the error message as a pointer,
+ * so we must copy that string unconditionally (if non-NULL).
+ */
+ {
+ char buffer[256];
+ char *msg = strerror_r(err, buffer, sizeof(buffer));
+ if(msg)
+ strncpy(buf, msg, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#elif defined(HAVE_STRERROR_R) && defined(HAVE_VXWORKS_STRERROR_R)
+ /*
+ * The vxworks-style strerror_r() does use the buffer we pass to the function.
+ * The buffer size should be at least MAXERRSTR_SIZE (150) defined in rtsold.h
+ */
+ {
+ char buffer[256];
+ if(OK == strerror_r(err, buffer))
+ strncpy(buf, buffer, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#else
+ {
+ char *msg = strerror(err);
+ if(msg)
+ strncpy(buf, msg, max);
+ else
+ snprintf(buf, max, "Unknown error %d", err);
+ }
+#endif
+
+#endif /* end of ! USE_WINSOCK */
+
+ buf[max] = '\0'; /* make sure the string is zero terminated */
+
+ /* strip trailing '\r\n' or '\n'. */
+ if((p = strrchr(buf,'\n')) != NULL && (p - buf) >= 2)
+ *p = '\0';
+ if((p = strrchr(buf,'\r')) != NULL && (p - buf) >= 1)
+ *p = '\0';
+
+ if(old_errno != ERRNO)
+ SET_ERRNO(old_errno);
+
+ return buf;
+}
+
+#ifdef USE_LIBIDN
+/*
+ * Return error-string for libidn status as returned from idna_to_ascii_lz().
+ */
+const char *Curl_idn_strerror (struct connectdata *conn, int err)
+{
+#ifdef HAVE_IDNA_STRERROR
+ (void)conn;
+ return idna_strerror((Idna_rc) err);
+#else
+ const char *str;
+ char *buf;
+ size_t max;
+
+ DEBUGASSERT(conn);
+
+ buf = conn->syserr_buf;
+ max = sizeof(conn->syserr_buf)-1;
+ *buf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ switch ((Idna_rc)err) {
+ case IDNA_SUCCESS:
+ str = "No error";
+ break;
+ case IDNA_STRINGPREP_ERROR:
+ str = "Error in string preparation";
+ break;
+ case IDNA_PUNYCODE_ERROR:
+ str = "Error in Punycode operation";
+ break;
+ case IDNA_CONTAINS_NON_LDH:
+ str = "Illegal ASCII characters";
+ break;
+ case IDNA_CONTAINS_MINUS:
+ str = "Contains minus";
+ break;
+ case IDNA_INVALID_LENGTH:
+ str = "Invalid output length";
+ break;
+ case IDNA_NO_ACE_PREFIX:
+ str = "No ACE prefix (\"xn--\")";
+ break;
+ case IDNA_ROUNDTRIP_VERIFY_ERROR:
+ str = "Round trip verify error";
+ break;
+ case IDNA_CONTAINS_ACE_PREFIX:
+ str = "Already have ACE prefix (\"xn--\")";
+ break;
+ case IDNA_ICONV_ERROR:
+ str = "Locale conversion failed";
+ break;
+ case IDNA_MALLOC_ERROR:
+ str = "Allocation failed";
+ break;
+ case IDNA_DLOPEN_ERROR:
+ str = "dlopen() error";
+ break;
+ default:
+ snprintf(buf, max, "error %d", err);
+ str = NULL;
+ break;
+ }
+#else
+ if((Idna_rc)err == IDNA_SUCCESS)
+ str = "No error";
+ else
+ str = "Error";
+#endif
+ if(str)
+ strncpy(buf, str, max);
+ buf[max] = '\0';
+ return (buf);
+#endif
+}
+#endif /* USE_LIBIDN */
+
+#ifdef USE_WINDOWS_SSPI
+const char *Curl_sspi_strerror (struct connectdata *conn, int err)
+{
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ char txtbuf[80];
+ char msgbuf[sizeof(conn->syserr_buf)];
+ char *p, *str, *msg = NULL;
+ bool msg_formatted = FALSE;
+ int old_errno;
+#endif
+ const char *txt;
+ char *outbuf;
+ size_t outmax;
+
+ DEBUGASSERT(conn);
+
+ outbuf = conn->syserr_buf;
+ outmax = sizeof(conn->syserr_buf)-1;
+ *outbuf = '\0';
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+
+ old_errno = ERRNO;
+
+ switch (err) {
+ case SEC_E_OK:
+ txt = "No error";
+ break;
+ case SEC_E_ALGORITHM_MISMATCH:
+ txt = "SEC_E_ALGORITHM_MISMATCH";
+ break;
+ case SEC_E_BAD_BINDINGS:
+ txt = "SEC_E_BAD_BINDINGS";
+ break;
+ case SEC_E_BAD_PKGID:
+ txt = "SEC_E_BAD_PKGID";
+ break;
+ case SEC_E_BUFFER_TOO_SMALL:
+ txt = "SEC_E_BUFFER_TOO_SMALL";
+ break;
+ case SEC_E_CANNOT_INSTALL:
+ txt = "SEC_E_CANNOT_INSTALL";
+ break;
+ case SEC_E_CANNOT_PACK:
+ txt = "SEC_E_CANNOT_PACK";
+ break;
+ case SEC_E_CERT_EXPIRED:
+ txt = "SEC_E_CERT_EXPIRED";
+ break;
+ case SEC_E_CERT_UNKNOWN:
+ txt = "SEC_E_CERT_UNKNOWN";
+ break;
+ case SEC_E_CERT_WRONG_USAGE:
+ txt = "SEC_E_CERT_WRONG_USAGE";
+ break;
+ case SEC_E_CONTEXT_EXPIRED:
+ txt = "SEC_E_CONTEXT_EXPIRED";
+ break;
+ case SEC_E_CROSSREALM_DELEGATION_FAILURE:
+ txt = "SEC_E_CROSSREALM_DELEGATION_FAILURE";
+ break;
+ case SEC_E_CRYPTO_SYSTEM_INVALID:
+ txt = "SEC_E_CRYPTO_SYSTEM_INVALID";
+ break;
+ case SEC_E_DECRYPT_FAILURE:
+ txt = "SEC_E_DECRYPT_FAILURE";
+ break;
+ case SEC_E_DELEGATION_POLICY:
+ txt = "SEC_E_DELEGATION_POLICY";
+ break;
+ case SEC_E_DELEGATION_REQUIRED:
+ txt = "SEC_E_DELEGATION_REQUIRED";
+ break;
+ case SEC_E_DOWNGRADE_DETECTED:
+ txt = "SEC_E_DOWNGRADE_DETECTED";
+ break;
+ case SEC_E_ENCRYPT_FAILURE:
+ txt = "SEC_E_ENCRYPT_FAILURE";
+ break;
+ case SEC_E_ILLEGAL_MESSAGE:
+ txt = "SEC_E_ILLEGAL_MESSAGE";
+ break;
+ case SEC_E_INCOMPLETE_CREDENTIALS:
+ txt = "SEC_E_INCOMPLETE_CREDENTIALS";
+ break;
+ case SEC_E_INCOMPLETE_MESSAGE:
+ txt = "SEC_E_INCOMPLETE_MESSAGE";
+ break;
+ case SEC_E_INSUFFICIENT_MEMORY:
+ txt = "SEC_E_INSUFFICIENT_MEMORY";
+ break;
+ case SEC_E_INTERNAL_ERROR:
+ txt = "SEC_E_INTERNAL_ERROR";
+ break;
+ case SEC_E_INVALID_HANDLE:
+ txt = "SEC_E_INVALID_HANDLE";
+ break;
+ case SEC_E_INVALID_PARAMETER:
+ txt = "SEC_E_INVALID_PARAMETER";
+ break;
+ case SEC_E_INVALID_TOKEN:
+ txt = "SEC_E_INVALID_TOKEN";
+ break;
+ case SEC_E_ISSUING_CA_UNTRUSTED:
+ txt = "SEC_E_ISSUING_CA_UNTRUSTED";
+ break;
+ case SEC_E_ISSUING_CA_UNTRUSTED_KDC:
+ txt = "SEC_E_ISSUING_CA_UNTRUSTED_KDC";
+ break;
+ case SEC_E_KDC_CERT_EXPIRED:
+ txt = "SEC_E_KDC_CERT_EXPIRED";
+ break;
+ case SEC_E_KDC_CERT_REVOKED:
+ txt = "SEC_E_KDC_CERT_REVOKED";
+ break;
+ case SEC_E_KDC_INVALID_REQUEST:
+ txt = "SEC_E_KDC_INVALID_REQUEST";
+ break;
+ case SEC_E_KDC_UNABLE_TO_REFER:
+ txt = "SEC_E_KDC_UNABLE_TO_REFER";
+ break;
+ case SEC_E_KDC_UNKNOWN_ETYPE:
+ txt = "SEC_E_KDC_UNKNOWN_ETYPE";
+ break;
+ case SEC_E_LOGON_DENIED:
+ txt = "SEC_E_LOGON_DENIED";
+ break;
+ case SEC_E_MAX_REFERRALS_EXCEEDED:
+ txt = "SEC_E_MAX_REFERRALS_EXCEEDED";
+ break;
+ case SEC_E_MESSAGE_ALTERED:
+ txt = "SEC_E_MESSAGE_ALTERED";
+ break;
+ case SEC_E_MULTIPLE_ACCOUNTS:
+ txt = "SEC_E_MULTIPLE_ACCOUNTS";
+ break;
+ case SEC_E_MUST_BE_KDC:
+ txt = "SEC_E_MUST_BE_KDC";
+ break;
+ case SEC_E_NOT_OWNER:
+ txt = "SEC_E_NOT_OWNER";
+ break;
+ case SEC_E_NO_AUTHENTICATING_AUTHORITY:
+ txt = "SEC_E_NO_AUTHENTICATING_AUTHORITY";
+ break;
+ case SEC_E_NO_CREDENTIALS:
+ txt = "SEC_E_NO_CREDENTIALS";
+ break;
+ case SEC_E_NO_IMPERSONATION:
+ txt = "SEC_E_NO_IMPERSONATION";
+ break;
+ case SEC_E_NO_IP_ADDRESSES:
+ txt = "SEC_E_NO_IP_ADDRESSES";
+ break;
+ case SEC_E_NO_KERB_KEY:
+ txt = "SEC_E_NO_KERB_KEY";
+ break;
+ case SEC_E_NO_PA_DATA:
+ txt = "SEC_E_NO_PA_DATA";
+ break;
+ case SEC_E_NO_S4U_PROT_SUPPORT:
+ txt = "SEC_E_NO_S4U_PROT_SUPPORT";
+ break;
+ case SEC_E_NO_TGT_REPLY:
+ txt = "SEC_E_NO_TGT_REPLY";
+ break;
+ case SEC_E_OUT_OF_SEQUENCE:
+ txt = "SEC_E_OUT_OF_SEQUENCE";
+ break;
+ case SEC_E_PKINIT_CLIENT_FAILURE:
+ txt = "SEC_E_PKINIT_CLIENT_FAILURE";
+ break;
+ case SEC_E_PKINIT_NAME_MISMATCH:
+ txt = "SEC_E_PKINIT_NAME_MISMATCH";
+ break;
+ case SEC_E_POLICY_NLTM_ONLY:
+ txt = "SEC_E_POLICY_NLTM_ONLY";
+ break;
+ case SEC_E_QOP_NOT_SUPPORTED:
+ txt = "SEC_E_QOP_NOT_SUPPORTED";
+ break;
+ case SEC_E_REVOCATION_OFFLINE_C:
+ txt = "SEC_E_REVOCATION_OFFLINE_C";
+ break;
+ case SEC_E_REVOCATION_OFFLINE_KDC:
+ txt = "SEC_E_REVOCATION_OFFLINE_KDC";
+ break;
+ case SEC_E_SECPKG_NOT_FOUND:
+ txt = "SEC_E_SECPKG_NOT_FOUND";
+ break;
+ case SEC_E_SECURITY_QOS_FAILED:
+ txt = "SEC_E_SECURITY_QOS_FAILED";
+ break;
+ case SEC_E_SHUTDOWN_IN_PROGRESS:
+ txt = "SEC_E_SHUTDOWN_IN_PROGRESS";
+ break;
+ case SEC_E_SMARTCARD_CERT_EXPIRED:
+ txt = "SEC_E_SMARTCARD_CERT_EXPIRED";
+ break;
+ case SEC_E_SMARTCARD_CERT_REVOKED:
+ txt = "SEC_E_SMARTCARD_CERT_REVOKED";
+ break;
+ case SEC_E_SMARTCARD_LOGON_REQUIRED:
+ txt = "SEC_E_SMARTCARD_LOGON_REQUIRED";
+ break;
+ case SEC_E_STRONG_CRYPTO_NOT_SUPPORTED:
+ txt = "SEC_E_STRONG_CRYPTO_NOT_SUPPORTED";
+ break;
+ case SEC_E_TARGET_UNKNOWN:
+ txt = "SEC_E_TARGET_UNKNOWN";
+ break;
+ case SEC_E_TIME_SKEW:
+ txt = "SEC_E_TIME_SKEW";
+ break;
+ case SEC_E_TOO_MANY_PRINCIPALS:
+ txt = "SEC_E_TOO_MANY_PRINCIPALS";
+ break;
+ case SEC_E_UNFINISHED_CONTEXT_DELETED:
+ txt = "SEC_E_UNFINISHED_CONTEXT_DELETED";
+ break;
+ case SEC_E_UNKNOWN_CREDENTIALS:
+ txt = "SEC_E_UNKNOWN_CREDENTIALS";
+ break;
+ case SEC_E_UNSUPPORTED_FUNCTION:
+ txt = "SEC_E_UNSUPPORTED_FUNCTION";
+ break;
+ case SEC_E_UNSUPPORTED_PREAUTH:
+ txt = "SEC_E_UNSUPPORTED_PREAUTH";
+ break;
+ case SEC_E_UNTRUSTED_ROOT:
+ txt = "SEC_E_UNTRUSTED_ROOT";
+ break;
+ case SEC_E_WRONG_CREDENTIAL_HANDLE:
+ txt = "SEC_E_WRONG_CREDENTIAL_HANDLE";
+ break;
+ case SEC_E_WRONG_PRINCIPAL:
+ txt = "SEC_E_WRONG_PRINCIPAL";
+ break;
+ case SEC_I_COMPLETE_AND_CONTINUE:
+ txt = "SEC_I_COMPLETE_AND_CONTINUE";
+ break;
+ case SEC_I_COMPLETE_NEEDED:
+ txt = "SEC_I_COMPLETE_NEEDED";
+ break;
+ case SEC_I_CONTEXT_EXPIRED:
+ txt = "SEC_I_CONTEXT_EXPIRED";
+ break;
+ case SEC_I_CONTINUE_NEEDED:
+ txt = "SEC_I_CONTINUE_NEEDED";
+ break;
+ case SEC_I_INCOMPLETE_CREDENTIALS:
+ txt = "SEC_I_INCOMPLETE_CREDENTIALS";
+ break;
+ case SEC_I_LOCAL_LOGON:
+ txt = "SEC_I_LOCAL_LOGON";
+ break;
+ case SEC_I_NO_LSA_CONTEXT:
+ txt = "SEC_I_NO_LSA_CONTEXT";
+ break;
+ case SEC_I_RENEGOTIATE:
+ txt = "SEC_I_RENEGOTIATE";
+ break;
+ case SEC_I_SIGNATURE_NEEDED:
+ txt = "SEC_I_SIGNATURE_NEEDED";
+ break;
+ default:
+ txt = "Unknown error";
+ }
+
+ if(err == SEC_E_OK)
+ strncpy(outbuf, txt, outmax);
+ else {
+ str = txtbuf;
+ snprintf(txtbuf, sizeof(txtbuf), "%s (0x%04X%04X)",
+ txt, (err >> 16) & 0xffff, err & 0xffff);
+ txtbuf[sizeof(txtbuf)-1] = '\0';
+
+#ifdef _WIN32_WCE
+ {
+ wchar_t wbuf[256];
+ wbuf[0] = L'\0';
+
+ if(FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, LANG_NEUTRAL,
+ wbuf, sizeof(wbuf)/sizeof(wchar_t), NULL)) {
+ wcstombs(msgbuf,wbuf,sizeof(msgbuf)-1);
+ msg_formatted = TRUE;
+ }
+ }
+#else
+ if(FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL, err, LANG_NEUTRAL,
+ msgbuf, sizeof(msgbuf)-1, NULL)) {
+ msg_formatted = TRUE;
+ }
+#endif
+ if(msg_formatted) {
+ msgbuf[sizeof(msgbuf)-1] = '\0';
+ /* strip trailing '\r\n' or '\n' */
+ if((p = strrchr(msgbuf,'\n')) != NULL && (p - msgbuf) >= 2)
+ *p = '\0';
+ if((p = strrchr(msgbuf,'\r')) != NULL && (p - msgbuf) >= 1)
+ *p = '\0';
+ msg = msgbuf;
+ }
+ if(msg)
+ snprintf(outbuf, outmax, "%s - %s", str, msg);
+ else
+ strncpy(outbuf, str, outmax);
+ }
+
+ if(old_errno != ERRNO)
+ SET_ERRNO(old_errno);
+
+#else
+
+ if(err == SEC_E_OK)
+ txt = "No error";
+ else
+ txt = "Error";
+
+ strncpy(outbuf, txt, outmax);
+
+#endif
+
+ outbuf[outmax] = '\0';
+
+ return outbuf;
+}
+#endif /* USE_WINDOWS_SSPI */
diff --git a/libs/libcurl/src/strerror.h b/libs/libcurl/src/strerror.h
new file mode 100644
index 0000000000..f1b22210ac
--- /dev/null
+++ b/libs/libcurl/src/strerror.h
@@ -0,0 +1,37 @@
+#ifndef HEADER_CURL_STRERROR_H
+#define HEADER_CURL_STRERROR_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2012, 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 "urldata.h"
+
+const char *Curl_strerror (struct connectdata *conn, int err);
+
+#ifdef USE_LIBIDN
+const char *Curl_idn_strerror (struct connectdata *conn, int err);
+#endif
+
+#ifdef USE_WINDOWS_SSPI
+const char *Curl_sspi_strerror (struct connectdata *conn, int err);
+#endif
+
+#endif /* HEADER_CURL_STRERROR_H */
diff --git a/libs/libcurl/src/strtok.c b/libs/libcurl/src/strtok.c
new file mode 100644
index 0000000000..0d31351f48
--- /dev/null
+++ b/libs/libcurl/src/strtok.c
@@ -0,0 +1,66 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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"
+
+#ifndef HAVE_STRTOK_R
+#include <stddef.h>
+
+#include "strtok.h"
+
+char *
+Curl_strtok_r(char *ptr, const char *sep, char **end)
+{
+ if(!ptr)
+ /* we got NULL input so then we get our last position instead */
+ ptr = *end;
+
+ /* pass all letters that are including in the separator string */
+ while(*ptr && strchr(sep, *ptr))
+ ++ptr;
+
+ if(*ptr) {
+ /* so this is where the next piece of string starts */
+ char *start = ptr;
+
+ /* set the end pointer to the first byte after the start */
+ *end = start + 1;
+
+ /* scan through the string to find where it ends, it ends on a
+ null byte or a character that exists in the separator string */
+ while(**end && !strchr(sep, **end))
+ ++*end;
+
+ if(**end) {
+ /* the end is not a null byte */
+ **end = '\0'; /* zero terminate it! */
+ ++*end; /* advance the last pointer to beyond the null byte */
+ }
+
+ return start; /* return the position where the string starts */
+ }
+
+ /* we ended up on a null byte, there are no more strings to find! */
+ return NULL;
+}
+
+#endif /* this was only compiled if strtok_r wasn't present */
diff --git a/libs/libcurl/src/strtok.h b/libs/libcurl/src/strtok.h
new file mode 100644
index 0000000000..1147d70d3c
--- /dev/null
+++ b/libs/libcurl/src/strtok.h
@@ -0,0 +1,34 @@
+#ifndef HEADER_CURL_STRTOK_H
+#define HEADER_CURL_STRTOK_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 <stddef.h>
+
+#ifndef HAVE_STRTOK_R
+char *Curl_strtok_r(char *s, const char *delim, char **last);
+#define strtok_r Curl_strtok_r
+#else
+#include <string.h>
+#endif
+
+#endif /* HEADER_CURL_STRTOK_H */
diff --git a/libs/libcurl/src/strtoofft.c b/libs/libcurl/src/strtoofft.c
new file mode 100644
index 0000000000..03a97e8c4d
--- /dev/null
+++ b/libs/libcurl/src/strtoofft.c
@@ -0,0 +1,188 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2011, 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 "strtoofft.h"
+
+/*
+ * NOTE:
+ *
+ * In the ISO C standard (IEEE Std 1003.1), there is a strtoimax() function we
+ * could use in case strtoll() doesn't exist... See
+ * http://www.opengroup.org/onlinepubs/009695399/functions/strtoimax.html
+ */
+
+#ifdef NEED_CURL_STRTOLL
+
+/* Range tests can be used for alphanum decoding if characters are consecutive,
+ like in ASCII. Else an array is scanned. Determine this condition now. */
+
+#if('9' - '0') != 9 || ('Z' - 'A') != 25 || ('z' - 'a') != 25
+
+#define NO_RANGE_TEST
+
+static const char valchars[] =
+ "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
+#endif
+
+static int get_char(char c, int base);
+
+/**
+ * Emulated version of the strtoll function. This extracts a long long
+ * value from the given input string and returns it.
+ */
+curl_off_t
+curlx_strtoll(const char *nptr, char **endptr, int base)
+{
+ char *end;
+ int is_negative = 0;
+ int overflow;
+ int i;
+ curl_off_t value = 0;
+ curl_off_t newval;
+
+ /* Skip leading whitespace. */
+ end = (char *)nptr;
+ while(ISSPACE(end[0])) {
+ end++;
+ }
+
+ /* Handle the sign, if any. */
+ if(end[0] == '-') {
+ is_negative = 1;
+ end++;
+ }
+ else if(end[0] == '+') {
+ end++;
+ }
+ else if(end[0] == '\0') {
+ /* We had nothing but perhaps some whitespace -- there was no number. */
+ if(endptr) {
+ *endptr = end;
+ }
+ return 0;
+ }
+
+ /* Handle special beginnings, if present and allowed. */
+ if(end[0] == '0' && end[1] == 'x') {
+ if(base == 16 || base == 0) {
+ end += 2;
+ base = 16;
+ }
+ }
+ else if(end[0] == '0') {
+ if(base == 8 || base == 0) {
+ end++;
+ base = 8;
+ }
+ }
+
+ /* Matching strtol, if the base is 0 and it doesn't look like
+ * the number is octal or hex, we assume it's base 10.
+ */
+ if(base == 0) {
+ base = 10;
+ }
+
+ /* Loop handling digits. */
+ value = 0;
+ overflow = 0;
+ for(i = get_char(end[0], base);
+ i != -1;
+ end++, i = get_char(end[0], base)) {
+ newval = base * value + i;
+ if(newval < value) {
+ /* We've overflowed. */
+ overflow = 1;
+ break;
+ }
+ else
+ value = newval;
+ }
+
+ if(!overflow) {
+ if(is_negative) {
+ /* Fix the sign. */
+ value *= -1;
+ }
+ }
+ else {
+ if(is_negative)
+ value = CURL_OFF_T_MIN;
+ else
+ value = CURL_OFF_T_MAX;
+
+ SET_ERRNO(ERANGE);
+ }
+
+ if(endptr)
+ *endptr = end;
+
+ return value;
+}
+
+/**
+ * Returns the value of c in the given base, or -1 if c cannot
+ * be interpreted properly in that base (i.e., is out of range,
+ * is a null, etc.).
+ *
+ * @param c the character to interpret according to base
+ * @param base the base in which to interpret c
+ *
+ * @return the value of c in base, or -1 if c isn't in range
+ */
+static int get_char(char c, int base)
+{
+#ifndef NO_RANGE_TEST
+ int value = -1;
+ if(c <= '9' && c >= '0') {
+ value = c - '0';
+ }
+ else if(c <= 'Z' && c >= 'A') {
+ value = c - 'A' + 10;
+ }
+ else if(c <= 'z' && c >= 'a') {
+ value = c - 'a' + 10;
+ }
+#else
+ const char * cp;
+ int value;
+
+ cp = memchr(valchars, c, 10 + 26 + 26);
+
+ if(!cp)
+ return -1;
+
+ value = cp - valchars;
+
+ if(value >= 10 + 26)
+ value -= 26; /* Lowercase. */
+#endif
+
+ if(value >= base) {
+ value = -1;
+ }
+
+ return value;
+}
+#endif /* Only present if we need strtoll, but don't have it. */
diff --git a/libs/libcurl/src/strtoofft.h b/libs/libcurl/src/strtoofft.h
new file mode 100644
index 0000000000..b812a67a0a
--- /dev/null
+++ b/libs/libcurl/src/strtoofft.h
@@ -0,0 +1,68 @@
+#ifndef HEADER_CURL_STRTOOFFT_H
+#define HEADER_CURL_STRTOOFFT_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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"
+
+/*
+ * Determine which string to integral data type conversion function we use
+ * to implement string conversion to our curl_off_t integral data type.
+ *
+ * Notice that curl_off_t might be 64 or 32 bit wide, and that it might use
+ * an underlying data type which might be 'long', 'int64_t', 'long long' or
+ * '__int64' and more remotely other data types.
+ *
+ * On systems where the size of curl_off_t is greater than the size of 'long'
+ * the conversion function to use is strtoll() if it is available, otherwise,
+ * we emulate its functionality with our own clone.
+ *
+ * On systems where the size of curl_off_t is smaller or equal than the size
+ * of 'long' the conversion function to use is strtol().
+ */
+
+#if (CURL_SIZEOF_CURL_OFF_T > CURL_SIZEOF_LONG)
+# ifdef HAVE_STRTOLL
+# define curlx_strtoofft strtoll
+# else
+# if defined(_MSC_VER) && (_MSC_VER >= 1300) && (_INTEGRAL_MAX_BITS >= 64)
+ _CRTIMP __int64 __cdecl _strtoi64(const char *, char **, int);
+# define curlx_strtoofft _strtoi64
+# else
+ curl_off_t curlx_strtoll(const char *nptr, char **endptr, int base);
+# define curlx_strtoofft curlx_strtoll
+# define NEED_CURL_STRTOLL 1
+# endif
+# endif
+#else
+# define curlx_strtoofft strtol
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T == 4)
+# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFF)
+#else
+ /* assume CURL_SIZEOF_CURL_OFF_T == 8 */
+# define CURL_OFF_T_MAX CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+#endif
+#define CURL_OFF_T_MIN (-CURL_OFF_T_MAX - CURL_OFF_T_C(1))
+
+#endif /* HEADER_CURL_STRTOOFFT_H */
diff --git a/libs/libcurl/src/telnet.c b/libs/libcurl/src/telnet.c
new file mode 100644
index 0000000000..366825078c
--- /dev/null
+++ b/libs/libcurl/src/telnet.c
@@ -0,0 +1,1678 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_TELNET
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "telnet.h"
+#include "connect.h"
+#include "progress.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#define TELOPTS
+#define TELCMDS
+
+#include "arpa_telnet.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "strequal.h"
+#include "rawstr.h"
+#include "warnless.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define SUBBUFSIZE 512
+
+#define CURL_SB_CLEAR(x) x->subpointer = x->subbuffer
+#define CURL_SB_TERM(x) \
+ do { \
+ x->subend = x->subpointer; \
+ CURL_SB_CLEAR(x); \
+ } WHILE_FALSE
+#define CURL_SB_ACCUM(x,c) \
+ do { \
+ if(x->subpointer < (x->subbuffer+sizeof x->subbuffer)) \
+ *x->subpointer++ = (c); \
+ } WHILE_FALSE
+
+#define CURL_SB_GET(x) ((*x->subpointer++)&0xff)
+#define CURL_SB_PEEK(x) ((*x->subpointer)&0xff)
+#define CURL_SB_EOF(x) (x->subpointer >= x->subend)
+#define CURL_SB_LEN(x) (x->subend - x->subpointer)
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define printoption(a,b,c,d) Curl_nop_stmt
+#endif
+
+#ifdef USE_WINSOCK
+typedef FARPROC WSOCK2_FUNC;
+static CURLcode check_wsock2 ( struct SessionHandle *data );
+#endif
+
+static
+CURLcode telrcv(struct connectdata *,
+ const unsigned char *inbuf, /* Data received from socket */
+ ssize_t count); /* Number of bytes received */
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct SessionHandle *data,
+ const char *direction,
+ int cmd, int option);
+#endif
+
+static void negotiate(struct connectdata *);
+static void send_negotiation(struct connectdata *, int cmd, int option);
+static void set_local_option(struct connectdata *, int cmd, int option);
+static void set_remote_option(struct connectdata *, int cmd, int option);
+
+static void printsub(struct SessionHandle *data,
+ int direction, unsigned char *pointer,
+ size_t length);
+static void suboption(struct connectdata *);
+static void sendsuboption(struct connectdata *conn, int option);
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done);
+static CURLcode telnet_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode send_telnet_data(struct connectdata *conn,
+ char *buffer, ssize_t nread);
+
+/* For negotiation compliant to RFC 1143 */
+#define CURL_NO 0
+#define CURL_YES 1
+#define CURL_WANTYES 2
+#define CURL_WANTNO 3
+
+#define CURL_EMPTY 0
+#define CURL_OPPOSITE 1
+
+/*
+ * Telnet receiver states for fsm
+ */
+typedef enum
+{
+ CURL_TS_DATA = 0,
+ CURL_TS_IAC,
+ CURL_TS_WILL,
+ CURL_TS_WONT,
+ CURL_TS_DO,
+ CURL_TS_DONT,
+ CURL_TS_CR,
+ CURL_TS_SB, /* sub-option collection */
+ CURL_TS_SE /* looking for sub-option end */
+} TelnetReceive;
+
+struct TELNET {
+ int please_negotiate;
+ int already_negotiated;
+ int us[256];
+ int usq[256];
+ int us_preferred[256];
+ int him[256];
+ int himq[256];
+ int him_preferred[256];
+ int subnegotiation[256];
+ char subopt_ttype[32]; /* Set with suboption TTYPE */
+ char subopt_xdisploc[128]; /* Set with suboption XDISPLOC */
+ unsigned short subopt_wsx; /* Set with suboption NAWS */
+ unsigned short subopt_wsy; /* Set with suboption NAWS */
+ struct curl_slist *telnet_vars; /* Environment variables */
+
+ /* suboptions */
+ unsigned char subbuffer[SUBBUFSIZE];
+ unsigned char *subpointer, *subend; /* buffer for sub-options */
+
+ TelnetReceive telrcv_state;
+};
+
+
+/*
+ * TELNET protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_telnet = {
+ "TELNET", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ telnet_do, /* do_it */
+ telnet_done, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_TELNET, /* defport */
+ CURLPROTO_TELNET, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+
+#ifdef USE_WINSOCK
+static CURLcode
+check_wsock2 ( struct SessionHandle *data )
+{
+ int err;
+ WORD wVersionRequested;
+ WSADATA wsaData;
+
+ DEBUGASSERT(data);
+
+ /* telnet requires at least WinSock 2.0 so ask for it. */
+ wVersionRequested = MAKEWORD(2, 0);
+
+ err = WSAStartup(wVersionRequested, &wsaData);
+
+ /* We must've called this once already, so this call */
+ /* should always succeed. But, just in case... */
+ if(err != 0) {
+ failf(data,"WSAStartup failed (%d)",err);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* We have to have a WSACleanup call for every successful */
+ /* WSAStartup call. */
+ WSACleanup();
+
+ /* Check that our version is supported */
+ if(LOBYTE(wsaData.wVersion) != LOBYTE(wVersionRequested) ||
+ HIBYTE(wsaData.wVersion) != HIBYTE(wVersionRequested)) {
+ /* Our version isn't supported */
+ failf(data,"insufficient winsock version to support "
+ "telnet");
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Our version is supported */
+ return CURLE_OK;
+}
+#endif
+
+static
+CURLcode init_telnet(struct connectdata *conn)
+{
+ struct TELNET *tn;
+
+ tn = calloc(1, sizeof(struct TELNET));
+ if(!tn)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->data->req.protop = tn; /* make us known */
+
+ tn->telrcv_state = CURL_TS_DATA;
+
+ /* Init suboptions */
+ CURL_SB_CLEAR(tn);
+
+ /* Set the options we want by default */
+ tn->us_preferred[CURL_TELOPT_SGA] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_SGA] = CURL_YES;
+
+ /* To be compliant with previous releases of libcurl
+ we enable this option by default. This behaviour
+ can be changed thanks to the "BINARY" option in
+ CURLOPT_TELNETOPTIONS
+ */
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_YES;
+
+ /* We must allow the server to echo what we sent
+ but it is not necessary to request the server
+ to do so (it might forces the server to close
+ the connection). Hence, we ignore ECHO in the
+ negotiate function
+ */
+ tn->him_preferred[CURL_TELOPT_ECHO] = CURL_YES;
+
+ /* Set the subnegotiation fields to send information
+ just after negotiation passed (do/will)
+
+ Default values are (0,0) initialized by calloc.
+ According to the RFC1013 it is valid:
+ A value equal to zero is acceptable for the width (or height),
+ and means that no character width (or height) is being sent.
+ In this case, the width (or height) that will be assumed by the
+ Telnet server is operating system specific (it will probably be
+ based upon the terminal type information that may have been sent
+ using the TERMINAL TYPE Telnet option). */
+ tn->subnegotiation[CURL_TELOPT_NAWS] = CURL_YES;
+ return CURLE_OK;
+}
+
+static void negotiate(struct connectdata *conn)
+{
+ int i;
+ struct TELNET *tn = (struct TELNET *) conn->data->req.protop;
+
+ for(i = 0;i < CURL_NTELOPTS;i++) {
+ if(i==CURL_TELOPT_ECHO)
+ continue;
+
+ if(tn->us_preferred[i] == CURL_YES)
+ set_local_option(conn, i, CURL_YES);
+
+ if(tn->him_preferred[i] == CURL_YES)
+ set_remote_option(conn, i, CURL_YES);
+ }
+}
+
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+static void printoption(struct SessionHandle *data,
+ const char *direction, int cmd, int option)
+{
+ const char *fmt;
+ const char *opt;
+
+ if(data->set.verbose) {
+ if(cmd == CURL_IAC) {
+ if(CURL_TELCMD_OK(option))
+ infof(data, "%s IAC %s\n", direction, CURL_TELCMD(option));
+ else
+ infof(data, "%s IAC %d\n", direction, option);
+ }
+ else {
+ fmt = (cmd == CURL_WILL) ? "WILL" : (cmd == CURL_WONT) ? "WONT" :
+ (cmd == CURL_DO) ? "DO" : (cmd == CURL_DONT) ? "DONT" : 0;
+ if(fmt) {
+ if(CURL_TELOPT_OK(option))
+ opt = CURL_TELOPT(option);
+ else if(option == CURL_TELOPT_EXOPL)
+ opt = "EXOPL";
+ else
+ opt = NULL;
+
+ if(opt)
+ infof(data, "%s %s %s\n", direction, fmt, opt);
+ else
+ infof(data, "%s %s %d\n", direction, fmt, option);
+ }
+ else
+ infof(data, "%s %d %d\n", direction, cmd, option);
+ }
+ }
+}
+#endif
+
+static void send_negotiation(struct connectdata *conn, int cmd, int option)
+{
+ unsigned char buf[3];
+ ssize_t bytes_written;
+ int err;
+ struct SessionHandle *data = conn->data;
+
+ buf[0] = CURL_IAC;
+ buf[1] = (unsigned char)cmd;
+ buf[2] = (unsigned char)option;
+
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], buf, 3);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+
+ printoption(conn->data, "SENT", cmd, option);
+}
+
+static
+void set_remote_option(struct connectdata *conn, int option, int newstate)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ if(newstate == CURL_YES) {
+ switch(tn->him[option]) {
+ case CURL_NO:
+ tn->him[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_DO, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->himq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else { /* NO */
+ switch(tn->him[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->him[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case CURL_OPPOSITE:
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->himq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static
+void rec_will(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ if(tn->him_preferred[option] == CURL_YES) {
+ tn->him[option] = CURL_YES;
+ send_negotiation(conn, CURL_DO, option);
+ }
+ else
+ send_negotiation(conn, CURL_DONT, option);
+
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ /* Error: DONT answered by WILL */
+ tn->him[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: DONT answered by WILL */
+ tn->him[option] = CURL_YES;
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_YES;
+ break;
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+ }
+ break;
+ }
+}
+
+static
+void rec_wont(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->him[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->him[option] = CURL_NO;
+ send_negotiation(conn, CURL_DONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
+ break;
+
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_WANTYES;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_DO, option);
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->himq[option]) {
+ case CURL_EMPTY:
+ tn->him[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ tn->him[option] = CURL_NO;
+ tn->himq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+}
+
+static void
+set_local_option(struct connectdata *conn, int option, int newstate)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ if(newstate == CURL_YES) {
+ switch(tn->us[option]) {
+ case CURL_NO:
+ tn->us[option] = CURL_WANTYES;
+ send_negotiation(conn, CURL_WILL, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for CURL_YES, queue the request */
+ tn->usq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: already queued an enable request */
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Error: already negotiating for enable */
+ break;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+ }
+ else { /* NO */
+ switch(tn->us[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->us[option] = CURL_WANTNO;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Already negotiating for NO */
+ break;
+ case CURL_OPPOSITE:
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->usq[option] = CURL_OPPOSITE;
+ break;
+ case CURL_OPPOSITE:
+ break;
+ }
+ break;
+ }
+ }
+}
+
+static
+void rec_do(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ if(tn->us_preferred[option] == CURL_YES) {
+ tn->us[option] = CURL_YES;
+ send_negotiation(conn, CURL_WILL, option);
+ if(tn->subnegotiation[option] == CURL_YES)
+ /* transmission of data option */
+ sendsuboption(conn, option);
+ }
+ else if(tn->subnegotiation[option] == CURL_YES) {
+ /* send information to achieve this option*/
+ tn->us[option] = CURL_YES;
+ send_negotiation(conn, CURL_WILL, option);
+ sendsuboption(conn, option);
+ }
+ else
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_YES:
+ /* Already enabled */
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ /* Error: DONT answered by WILL */
+ tn->us[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ /* Error: DONT answered by WILL */
+ tn->us[option] = CURL_YES;
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_YES;
+ if(tn->subnegotiation[option] == CURL_YES) {
+ /* transmission of data option */
+ sendsuboption(conn, option);
+ }
+ break;
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTNO;
+ tn->himq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+ }
+ break;
+ }
+}
+
+static
+void rec_dont(struct connectdata *conn, int option)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ switch(tn->us[option]) {
+ case CURL_NO:
+ /* Already disabled */
+ break;
+
+ case CURL_YES:
+ tn->us[option] = CURL_NO;
+ send_negotiation(conn, CURL_WONT, option);
+ break;
+
+ case CURL_WANTNO:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
+ break;
+
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_WANTYES;
+ tn->usq[option] = CURL_EMPTY;
+ send_negotiation(conn, CURL_WILL, option);
+ break;
+ }
+ break;
+
+ case CURL_WANTYES:
+ switch(tn->usq[option]) {
+ case CURL_EMPTY:
+ tn->us[option] = CURL_NO;
+ break;
+ case CURL_OPPOSITE:
+ tn->us[option] = CURL_NO;
+ tn->usq[option] = CURL_EMPTY;
+ break;
+ }
+ break;
+ }
+}
+
+
+static void printsub(struct SessionHandle *data,
+ int direction, /* '<' or '>' */
+ unsigned char *pointer, /* where suboption data is */
+ size_t length) /* length of suboption data */
+{
+ unsigned int i = 0;
+ unsigned short *pval;
+
+ if(data->set.verbose) {
+ if(direction) {
+ infof(data, "%s IAC SB ", (direction == '<')? "RCVD":"SENT");
+ if(length >= 3) {
+ int j;
+
+ i = pointer[length-2];
+ j = pointer[length-1];
+
+ if(i != CURL_IAC || j != CURL_SE) {
+ infof(data, "(terminated by ");
+ if(CURL_TELOPT_OK(i))
+ infof(data, "%s ", CURL_TELOPT(i));
+ else if(CURL_TELCMD_OK(i))
+ infof(data, "%s ", CURL_TELCMD(i));
+ else
+ infof(data, "%u ", i);
+ if(CURL_TELOPT_OK(j))
+ infof(data, "%s", CURL_TELOPT(j));
+ else if(CURL_TELCMD_OK(j))
+ infof(data, "%s", CURL_TELCMD(j));
+ else
+ infof(data, "%d", j);
+ infof(data, ", not IAC SE!) ");
+ }
+ }
+ length -= 2;
+ }
+ if(length < 1) {
+ infof(data, "(Empty suboption?)");
+ return;
+ }
+
+ if(CURL_TELOPT_OK(pointer[0])) {
+ switch(pointer[0]) {
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
+ case CURL_TELOPT_NEW_ENVIRON:
+ case CURL_TELOPT_NAWS:
+ infof(data, "%s", CURL_TELOPT(pointer[0]));
+ break;
+ default:
+ infof(data, "%s (unsupported)", CURL_TELOPT(pointer[0]));
+ break;
+ }
+ }
+ else
+ infof(data, "%d (unknown)", pointer[i]);
+
+ switch(pointer[0]) {
+ case CURL_TELOPT_NAWS:
+ pval = (unsigned short*)(pointer+1);
+ infof(data, "Width: %hu ; Height: %hu",
+ ntohs(pval[0]), ntohs(pval[1]));
+ break;
+ default:
+ switch(pointer[1]) {
+ case CURL_TELQUAL_IS:
+ infof(data, " IS");
+ break;
+ case CURL_TELQUAL_SEND:
+ infof(data, " SEND");
+ break;
+ case CURL_TELQUAL_INFO:
+ infof(data, " INFO/REPLY");
+ break;
+ case CURL_TELQUAL_NAME:
+ infof(data, " NAME");
+ break;
+ }
+
+ switch(pointer[0]) {
+ case CURL_TELOPT_TTYPE:
+ case CURL_TELOPT_XDISPLOC:
+ pointer[length] = 0;
+ infof(data, " \"%s\"", &pointer[2]);
+ break;
+ case CURL_TELOPT_NEW_ENVIRON:
+ if(pointer[1] == CURL_TELQUAL_IS) {
+ infof(data, " ");
+ for(i = 3;i < length;i++) {
+ switch(pointer[i]) {
+ case CURL_NEW_ENV_VAR:
+ infof(data, ", ");
+ break;
+ case CURL_NEW_ENV_VALUE:
+ infof(data, " = ");
+ break;
+ default:
+ infof(data, "%c", pointer[i]);
+ break;
+ }
+ }
+ }
+ break;
+ default:
+ for(i = 2; i < length; i++)
+ infof(data, " %.2x", pointer[i]);
+ break;
+ }
+ }
+ if(direction)
+ infof(data, "\n");
+ }
+}
+
+static CURLcode check_telnet_options(struct connectdata *conn)
+{
+ struct curl_slist *head;
+ struct curl_slist *beg;
+ char option_keyword[128];
+ char option_arg[256];
+ struct SessionHandle *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ CURLcode result = CURLE_OK;
+ int binary_option;
+
+ /* Add the user name as an environment variable if it
+ was given on the command line */
+ if(conn->bits.user_passwd) {
+ snprintf(option_arg, sizeof(option_arg), "USER,%s", conn->user);
+ beg = curl_slist_append(tn->telnet_vars, option_arg);
+ if(!beg) {
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ tn->telnet_vars = beg;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+ }
+
+ for(head = data->set.telnet_options; head; head=head->next) {
+ if(sscanf(head->data, "%127[^= ]%*[ =]%255s",
+ option_keyword, option_arg) == 2) {
+
+ /* Terminal type */
+ if(Curl_raw_equal(option_keyword, "TTYPE")) {
+ strncpy(tn->subopt_ttype, option_arg, 31);
+ tn->subopt_ttype[31] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_TTYPE] = CURL_YES;
+ continue;
+ }
+
+ /* Display variable */
+ if(Curl_raw_equal(option_keyword, "XDISPLOC")) {
+ strncpy(tn->subopt_xdisploc, option_arg, 127);
+ tn->subopt_xdisploc[127] = 0; /* String termination */
+ tn->us_preferred[CURL_TELOPT_XDISPLOC] = CURL_YES;
+ continue;
+ }
+
+ /* Environment variable */
+ if(Curl_raw_equal(option_keyword, "NEW_ENV")) {
+ beg = curl_slist_append(tn->telnet_vars, option_arg);
+ if(!beg) {
+ result = CURLE_OUT_OF_MEMORY;
+ break;
+ }
+ tn->telnet_vars = beg;
+ tn->us_preferred[CURL_TELOPT_NEW_ENVIRON] = CURL_YES;
+ continue;
+ }
+
+ /* Window Size */
+ if(Curl_raw_equal(option_keyword, "WS")) {
+ if(sscanf(option_arg, "%hu%*[xX]%hu",
+ &tn->subopt_wsx, &tn->subopt_wsy) == 2)
+ tn->us_preferred[CURL_TELOPT_NAWS] = CURL_YES;
+ else {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_TELNET_OPTION_SYNTAX;
+ break;
+ }
+ continue;
+ }
+
+ /* To take care or not of the 8th bit in data exchange */
+ if(Curl_raw_equal(option_keyword, "BINARY")) {
+ binary_option=atoi(option_arg);
+ if(binary_option!=1) {
+ tn->us_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ tn->him_preferred[CURL_TELOPT_BINARY] = CURL_NO;
+ }
+ continue;
+ }
+
+ failf(data, "Unknown telnet option %s", head->data);
+ result = CURLE_UNKNOWN_TELNET_OPTION;
+ break;
+ }
+ else {
+ failf(data, "Syntax error in telnet option: %s", head->data);
+ result = CURLE_TELNET_OPTION_SYNTAX;
+ break;
+ }
+ }
+
+ if(result) {
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+ }
+
+ return result;
+}
+
+/*
+ * suboption()
+ *
+ * Look at the sub-option buffer, and try to be helpful to the other
+ * side.
+ */
+
+static void suboption(struct connectdata *conn)
+{
+ struct curl_slist *v;
+ unsigned char temp[2048];
+ ssize_t bytes_written;
+ size_t len;
+ size_t tmplen;
+ int err;
+ char varname[128];
+ char varval[128];
+ struct SessionHandle *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+ printsub(data, '<', (unsigned char *)tn->subbuffer, CURL_SB_LEN(tn)+2);
+ switch (CURL_SB_GET(tn)) {
+ case CURL_TELOPT_TTYPE:
+ len = strlen(tn->subopt_ttype) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_TTYPE,
+ CURL_TELQUAL_IS, tn->subopt_ttype, CURL_IAC, CURL_SE);
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case CURL_TELOPT_XDISPLOC:
+ len = strlen(tn->subopt_xdisploc) + 4 + 2;
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c%s%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_XDISPLOC,
+ CURL_TELQUAL_IS, tn->subopt_xdisploc, CURL_IAC, CURL_SE);
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ case CURL_TELOPT_NEW_ENVIRON:
+ snprintf((char *)temp, sizeof(temp),
+ "%c%c%c%c", CURL_IAC, CURL_SB, CURL_TELOPT_NEW_ENVIRON,
+ CURL_TELQUAL_IS);
+ len = 4;
+
+ for(v = tn->telnet_vars;v;v = v->next) {
+ tmplen = (strlen(v->data) + 1);
+ /* Add the variable only if it fits */
+ if(len + tmplen < sizeof(temp)-6) {
+ sscanf(v->data, "%127[^,],%127s", varname, varval);
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%s%c%s", CURL_NEW_ENV_VAR, varname,
+ CURL_NEW_ENV_VALUE, varval);
+ len += tmplen;
+ }
+ }
+ snprintf((char *)&temp[len], sizeof(temp) - len,
+ "%c%c", CURL_IAC, CURL_SE);
+ len += 2;
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], temp, len);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data,"Sending data failed (%d)",err);
+ }
+ printsub(data, '>', &temp[2], len-2);
+ break;
+ }
+ return;
+}
+
+
+/*
+ * sendsuboption()
+ *
+ * Send suboption information to the server side.
+ */
+
+static void sendsuboption(struct connectdata *conn, int option)
+{
+ ssize_t bytes_written;
+ int err;
+ unsigned short x, y;
+ unsigned char*uc1, *uc2;
+
+ struct SessionHandle *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+ switch (option) {
+ case CURL_TELOPT_NAWS:
+ /* We prepare data to be sent */
+ CURL_SB_CLEAR(tn);
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SB);
+ CURL_SB_ACCUM(tn, CURL_TELOPT_NAWS);
+ /* We must deal either with litte or big endien processors */
+ /* Window size must be sent according to the 'network order' */
+ x=htons(tn->subopt_wsx);
+ y=htons(tn->subopt_wsy);
+ uc1 = (unsigned char*)&x;
+ uc2 = (unsigned char*)&y;
+ CURL_SB_ACCUM(tn, uc1[0]);
+ CURL_SB_ACCUM(tn, uc1[1]);
+ CURL_SB_ACCUM(tn, uc2[0]);
+ CURL_SB_ACCUM(tn, uc2[1]);
+
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SE);
+ CURL_SB_TERM(tn);
+ /* data suboption is now ready */
+
+ printsub(data, '>', (unsigned char *)tn->subbuffer+2,
+ CURL_SB_LEN(tn)-2);
+
+ /* we send the header of the suboption... */
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer, 3);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data, "Sending data failed (%d)", err);
+ }
+ /* ... then the window size with the send_telnet_data() function
+ to deal with 0xFF cases ... */
+ send_telnet_data(conn, (char *)tn->subbuffer+3, 4);
+ /* ... and the footer */
+ bytes_written = swrite(conn->sock[FIRSTSOCKET], tn->subbuffer+7, 2);
+ if(bytes_written < 0) {
+ err = SOCKERRNO;
+ failf(data, "Sending data failed (%d)", err);
+ }
+ break;
+ }
+}
+
+
+static
+CURLcode telrcv(struct connectdata *conn,
+ const unsigned char *inbuf, /* Data received from socket */
+ ssize_t count) /* Number of bytes received */
+{
+ unsigned char c;
+ CURLcode result;
+ int in = 0;
+ int startwrite=-1;
+ struct SessionHandle *data = conn->data;
+ struct TELNET *tn = (struct TELNET *)data->req.protop;
+
+#define startskipping() \
+ if(startwrite >= 0) { \
+ result = Curl_client_write(conn, \
+ CLIENTWRITE_BODY, \
+ (char *)&inbuf[startwrite], \
+ in-startwrite); \
+ if(result != CURLE_OK) \
+ return result; \
+ } \
+ startwrite = -1
+
+#define writebyte() \
+ if(startwrite < 0) \
+ startwrite = in
+
+#define bufferflush() startskipping()
+
+ while(count--) {
+ c = inbuf[in];
+
+ switch (tn->telrcv_state) {
+ case CURL_TS_CR:
+ tn->telrcv_state = CURL_TS_DATA;
+ if(c == '\0') {
+ startskipping();
+ break; /* Ignore \0 after CR */
+ }
+ writebyte();
+ break;
+
+ case CURL_TS_DATA:
+ if(c == CURL_IAC) {
+ tn->telrcv_state = CURL_TS_IAC;
+ startskipping();
+ break;
+ }
+ else if(c == '\r')
+ tn->telrcv_state = CURL_TS_CR;
+ writebyte();
+ break;
+
+ case CURL_TS_IAC:
+ process_iac:
+ DEBUGASSERT(startwrite < 0);
+ switch (c) {
+ case CURL_WILL:
+ tn->telrcv_state = CURL_TS_WILL;
+ break;
+ case CURL_WONT:
+ tn->telrcv_state = CURL_TS_WONT;
+ break;
+ case CURL_DO:
+ tn->telrcv_state = CURL_TS_DO;
+ break;
+ case CURL_DONT:
+ tn->telrcv_state = CURL_TS_DONT;
+ break;
+ case CURL_SB:
+ CURL_SB_CLEAR(tn);
+ tn->telrcv_state = CURL_TS_SB;
+ break;
+ case CURL_IAC:
+ tn->telrcv_state = CURL_TS_DATA;
+ writebyte();
+ break;
+ case CURL_DM:
+ case CURL_NOP:
+ case CURL_GA:
+ default:
+ tn->telrcv_state = CURL_TS_DATA;
+ printoption(data, "RCVD", CURL_IAC, c);
+ break;
+ }
+ break;
+
+ case CURL_TS_WILL:
+ printoption(data, "RCVD", CURL_WILL, c);
+ tn->please_negotiate = 1;
+ rec_will(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_WONT:
+ printoption(data, "RCVD", CURL_WONT, c);
+ tn->please_negotiate = 1;
+ rec_wont(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_DO:
+ printoption(data, "RCVD", CURL_DO, c);
+ tn->please_negotiate = 1;
+ rec_do(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_DONT:
+ printoption(data, "RCVD", CURL_DONT, c);
+ tn->please_negotiate = 1;
+ rec_dont(conn, c);
+ tn->telrcv_state = CURL_TS_DATA;
+ break;
+
+ case CURL_TS_SB:
+ if(c == CURL_IAC)
+ tn->telrcv_state = CURL_TS_SE;
+ else
+ CURL_SB_ACCUM(tn,c);
+ break;
+
+ case CURL_TS_SE:
+ if(c != CURL_SE) {
+ if(c != CURL_IAC) {
+ /*
+ * This is an error. We only expect to get "IAC IAC" or "IAC SE".
+ * Several things may have happened. An IAC was not doubled, the
+ * IAC SE was left off, or another option got inserted into the
+ * suboption are all possibilities. If we assume that the IAC was
+ * not doubled, and really the IAC SE was left off, we could get
+ * into an infinate loop here. So, instead, we terminate the
+ * suboption, and process the partial suboption if we can.
+ */
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, c);
+ tn->subpointer -= 2;
+ CURL_SB_TERM(tn);
+
+ printoption(data, "In SUBOPTION processing, RCVD", CURL_IAC, c);
+ suboption(conn); /* handle sub-option */
+ tn->telrcv_state = CURL_TS_IAC;
+ goto process_iac;
+ }
+ CURL_SB_ACCUM(tn,c);
+ tn->telrcv_state = CURL_TS_SB;
+ }
+ else
+ {
+ CURL_SB_ACCUM(tn, CURL_IAC);
+ CURL_SB_ACCUM(tn, CURL_SE);
+ tn->subpointer -= 2;
+ CURL_SB_TERM(tn);
+ suboption(conn); /* handle sub-option */
+ tn->telrcv_state = CURL_TS_DATA;
+ }
+ break;
+ }
+ ++in;
+ }
+ bufferflush();
+ return CURLE_OK;
+}
+
+/* Escape and send a telnet data block */
+/* TODO: write large chunks of data instead of one byte at a time */
+static CURLcode send_telnet_data(struct connectdata *conn,
+ char *buffer, ssize_t nread)
+{
+ unsigned char outbuf[2];
+ ssize_t bytes_written, total_written;
+ int out_count;
+ CURLcode rc = CURLE_OK;
+
+ while(rc == CURLE_OK && nread--) {
+ outbuf[0] = *buffer++;
+ out_count = 1;
+ if(outbuf[0] == CURL_IAC)
+ outbuf[out_count++] = CURL_IAC;
+
+ total_written = 0;
+ do {
+ /* Make sure socket is writable to avoid EWOULDBLOCK condition */
+ struct pollfd pfd[1];
+ pfd[0].fd = conn->sock[FIRSTSOCKET];
+ pfd[0].events = POLLOUT;
+ switch (Curl_poll(pfd, 1, -1)) {
+ case -1: /* error, abort writing */
+ case 0: /* timeout (will never happen) */
+ rc = CURLE_SEND_ERROR;
+ break;
+ default: /* write! */
+ bytes_written = 0;
+ rc = Curl_write(conn, conn->sock[FIRSTSOCKET], outbuf+total_written,
+ out_count-total_written, &bytes_written);
+ total_written += bytes_written;
+ break;
+ }
+ /* handle partial write */
+ } while(rc == CURLE_OK && total_written < out_count);
+ }
+ return rc;
+}
+
+static CURLcode telnet_done(struct connectdata *conn,
+ CURLcode status, bool premature)
+{
+ struct TELNET *tn = (struct TELNET *)conn->data->req.protop;
+ (void)status; /* unused */
+ (void)premature; /* not used */
+
+ if(!tn)
+ return CURLE_OK;
+
+ curl_slist_free_all(tn->telnet_vars);
+ tn->telnet_vars = NULL;
+
+ Curl_safefree(conn->data->req.protop);
+
+ return CURLE_OK;
+}
+
+static CURLcode telnet_do(struct connectdata *conn, bool *done)
+{
+ CURLcode code;
+ struct SessionHandle *data = conn->data;
+ curl_socket_t sockfd = conn->sock[FIRSTSOCKET];
+#ifdef USE_WINSOCK
+ HMODULE wsock2;
+ WSOCK2_FUNC close_event_func;
+ WSOCK2_FUNC create_event_func;
+ WSOCK2_FUNC event_select_func;
+ WSOCK2_FUNC enum_netevents_func;
+ WSAEVENT event_handle;
+ WSANETWORKEVENTS events;
+ HANDLE stdin_handle;
+ HANDLE objs[2];
+ DWORD obj_count;
+ DWORD wait_timeout;
+ DWORD waitret;
+ DWORD readfile_read;
+ int err;
+#else
+ int interval_ms;
+ struct pollfd pfd[2];
+ int poll_cnt;
+ curl_off_t total_dl = 0;
+ curl_off_t total_ul = 0;
+#endif
+ ssize_t nread;
+ struct timeval now;
+ bool keepon = TRUE;
+ char *buf = data->state.buffer;
+ struct TELNET *tn;
+
+ *done = TRUE; /* unconditionally */
+
+ code = init_telnet(conn);
+ if(code)
+ return code;
+
+ tn = (struct TELNET *)data->req.protop;
+
+ code = check_telnet_options(conn);
+ if(code)
+ return code;
+
+#ifdef USE_WINSOCK
+ /*
+ ** This functionality only works with WinSock >= 2.0. So,
+ ** make sure have it.
+ */
+ code = check_wsock2(data);
+ if(code)
+ return code;
+
+ /* OK, so we have WinSock 2.0. We need to dynamically */
+ /* load ws2_32.dll and get the function pointers we need. */
+ wsock2 = LoadLibrary(TEXT("WS2_32.DLL"));
+ if(wsock2 == NULL) {
+ failf(data,"failed to load WS2_32.DLL (%d)", ERRNO);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Grab a pointer to WSACreateEvent */
+ create_event_func = GetProcAddress(wsock2,"WSACreateEvent");
+ if(create_event_func == NULL) {
+ failf(data,"failed to find WSACreateEvent function (%d)",
+ ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSACloseEvent */
+ close_event_func = GetProcAddress(wsock2,"WSACloseEvent");
+ if(close_event_func == NULL) {
+ failf(data,"failed to find WSACloseEvent function (%d)",
+ ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEventSelect */
+ event_select_func = GetProcAddress(wsock2,"WSAEventSelect");
+ if(event_select_func == NULL) {
+ failf(data,"failed to find WSAEventSelect function (%d)",
+ ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* And WSAEnumNetworkEvents */
+ enum_netevents_func = GetProcAddress(wsock2,"WSAEnumNetworkEvents");
+ if(enum_netevents_func == NULL) {
+ failf(data,"failed to find WSAEnumNetworkEvents function (%d)",
+ ERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* We want to wait for both stdin and the socket. Since
+ ** the select() function in winsock only works on sockets
+ ** we have to use the WaitForMultipleObjects() call.
+ */
+
+ /* First, create a sockets event object */
+ event_handle = (WSAEVENT)create_event_func();
+ if(event_handle == WSA_INVALID_EVENT) {
+ failf(data,"WSACreateEvent failed (%d)", SOCKERRNO);
+ FreeLibrary(wsock2);
+ return CURLE_FAILED_INIT;
+ }
+
+ /* Tell winsock what events we want to listen to */
+ if(event_select_func(sockfd, event_handle, FD_READ|FD_CLOSE) ==
+ SOCKET_ERROR) {
+ close_event_func(event_handle);
+ FreeLibrary(wsock2);
+ return CURLE_OK;
+ }
+
+ /* The get the Windows file handle for stdin */
+ stdin_handle = GetStdHandle(STD_INPUT_HANDLE);
+
+ /* Create the list of objects to wait for */
+ objs[0] = event_handle;
+ objs[1] = stdin_handle;
+
+ /* If stdin_handle is a pipe, use PeekNamedPipe() method to check it,
+ else use the old WaitForMultipleObjects() way */
+ if(GetFileType(stdin_handle) == FILE_TYPE_PIPE ||
+ data->set.is_fread_set) {
+ /* Don't wait for stdin_handle, just wait for event_handle */
+ obj_count = 1;
+ /* Check stdin_handle per 100 milliseconds */
+ wait_timeout = 100;
+ }
+ else {
+ obj_count = 2;
+ wait_timeout = 1000;
+ }
+
+ /* Keep on listening and act on events */
+ while(keepon) {
+ waitret = WaitForMultipleObjects(obj_count, objs, FALSE, wait_timeout);
+ switch(waitret) {
+ case WAIT_TIMEOUT:
+ {
+ for(;;) {
+ if(obj_count == 1) {
+ /* read from user-supplied method */
+ code = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
+ if(code == CURL_READFUNC_ABORT) {
+ keepon = FALSE;
+ code = CURLE_READ_ERROR;
+ break;
+ }
+
+ if(code == CURL_READFUNC_PAUSE)
+ break;
+
+ if(code == 0) /* no bytes */
+ break;
+
+ readfile_read = code; /* fall thru with number of bytes read */
+ }
+ else {
+ /* read from stdin */
+ if(!PeekNamedPipe(stdin_handle, NULL, 0, NULL,
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ code = CURLE_READ_ERROR;
+ break;
+ }
+
+ if(!readfile_read)
+ break;
+
+ if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ code = CURLE_READ_ERROR;
+ break;
+ }
+ }
+
+ code = send_telnet_data(conn, buf, readfile_read);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ }
+ break;
+
+ case WAIT_OBJECT_0 + 1:
+ {
+ if(!ReadFile(stdin_handle, buf, sizeof(data->state.buffer),
+ &readfile_read, NULL)) {
+ keepon = FALSE;
+ code = CURLE_READ_ERROR;
+ break;
+ }
+
+ code = send_telnet_data(conn, buf, readfile_read);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+ }
+ break;
+
+ case WAIT_OBJECT_0:
+
+ if(SOCKET_ERROR == enum_netevents_func(sockfd, event_handle, &events)) {
+ if((err = SOCKERRNO) != EINPROGRESS) {
+ infof(data,"WSAEnumNetworkEvents failed (%d)", err);
+ keepon = FALSE;
+ code = CURLE_READ_ERROR;
+ }
+ break;
+ }
+ if(events.lNetworkEvents & FD_READ) {
+ /* read data from network */
+ code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+ /* read would've blocked. Loop again */
+ if(code == CURLE_AGAIN)
+ break;
+ /* returned not-zero, this an error */
+ else if(code) {
+ keepon = FALSE;
+ break;
+ }
+ /* returned zero but actually received 0 or less here,
+ the server closed the connection and we bail out */
+ else if(nread <= 0) {
+ keepon = FALSE;
+ break;
+ }
+
+ code = telrcv(conn, (unsigned char *)buf, nread);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(tn->please_negotiate && !tn->already_negotiated) {
+ negotiate(conn);
+ tn->already_negotiated = 1;
+ }
+ }
+ if(events.lNetworkEvents & FD_CLOSE) {
+ keepon = FALSE;
+ }
+ break;
+
+ }
+
+ if(data->set.timeout) {
+ now = Curl_tvnow();
+ if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ failf(data, "Time-out");
+ code = CURLE_OPERATION_TIMEDOUT;
+ keepon = FALSE;
+ }
+ }
+ }
+
+ /* We called WSACreateEvent, so call WSACloseEvent */
+ if(!close_event_func(event_handle)) {
+ infof(data,"WSACloseEvent failed (%d)", SOCKERRNO);
+ }
+
+ /* "Forget" pointers into the library we're about to free */
+ create_event_func = NULL;
+ close_event_func = NULL;
+ event_select_func = NULL;
+ enum_netevents_func = NULL;
+
+ /* We called LoadLibrary, so call FreeLibrary */
+ if(!FreeLibrary(wsock2))
+ infof(data,"FreeLibrary(wsock2) failed (%d)", ERRNO);
+#else
+ pfd[0].fd = sockfd;
+ pfd[0].events = POLLIN;
+
+ if(conn->fread_func != (curl_read_callback)fread) {
+ poll_cnt = 1;
+ interval_ms = 100; /* poll user-supplied read function */
+ }
+ else {
+ /* really using fread, so infile is a FILE* */
+ pfd[1].fd = fileno((FILE *)conn->fread_in);
+ pfd[1].events = POLLIN;
+ poll_cnt = 2;
+ interval_ms = 1 * 1000;
+ }
+
+ while(keepon) {
+ switch (Curl_poll(pfd, poll_cnt, interval_ms)) {
+ case -1: /* error, stop reading */
+ keepon = FALSE;
+ continue;
+ case 0: /* timeout */
+ pfd[0].revents = 0;
+ pfd[1].revents = 0;
+ /* fall through */
+ default: /* read! */
+ if(pfd[0].revents & POLLIN) {
+ /* read data from network */
+ code = Curl_read(conn, sockfd, buf, BUFSIZE - 1, &nread);
+ /* read would've blocked. Loop again */
+ if(code == CURLE_AGAIN)
+ break;
+ /* returned not-zero, this an error */
+ else if(code) {
+ keepon = FALSE;
+ break;
+ }
+ /* returned zero but actually received 0 or less here,
+ the server closed the connection and we bail out */
+ else if(nread <= 0) {
+ keepon = FALSE;
+ break;
+ }
+
+ total_dl += nread;
+ Curl_pgrsSetDownloadCounter(data, total_dl);
+ code = telrcv(conn, (unsigned char *)buf, nread);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+
+ /* Negotiate if the peer has started negotiating,
+ otherwise don't. We don't want to speak telnet with
+ non-telnet servers, like POP or SMTP. */
+ if(tn->please_negotiate && !tn->already_negotiated) {
+ negotiate(conn);
+ tn->already_negotiated = 1;
+ }
+ }
+
+ nread = 0;
+ if(poll_cnt == 2) {
+ if(pfd[1].revents & POLLIN) { /* read from in file */
+ nread = read(pfd[1].fd, buf, BUFSIZE - 1);
+ }
+ }
+ else {
+ /* read from user-supplied method */
+ nread = (int)conn->fread_func(buf, 1, BUFSIZE - 1, conn->fread_in);
+ if(nread == CURL_READFUNC_ABORT) {
+ keepon = FALSE;
+ break;
+ }
+ if(nread == CURL_READFUNC_PAUSE)
+ break;
+ }
+
+ if(nread > 0) {
+ code = send_telnet_data(conn, buf, nread);
+ if(code) {
+ keepon = FALSE;
+ break;
+ }
+ total_ul += nread;
+ Curl_pgrsSetUploadCounter(data, total_ul);
+ }
+ else if(nread < 0)
+ keepon = FALSE;
+
+ break;
+ } /* poll switch statement */
+
+ if(data->set.timeout) {
+ now = Curl_tvnow();
+ if(Curl_tvdiff(now, conn->created) >= data->set.timeout) {
+ failf(data, "Time-out");
+ code = CURLE_OPERATION_TIMEDOUT;
+ keepon = FALSE;
+ }
+ }
+
+ if(Curl_pgrsUpdate(conn)) {
+ code = CURLE_ABORTED_BY_CALLBACK;
+ break;
+ }
+ }
+#endif
+ /* mark this as "no further transfer wanted" */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+
+ return code;
+}
+#endif
diff --git a/libs/libcurl/src/telnet.h b/libs/libcurl/src/telnet.h
new file mode 100644
index 0000000000..ddb9e5473d
--- /dev/null
+++ b/libs/libcurl/src/telnet.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TELNET_H
+#define HEADER_CURL_TELNET_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TELNET
+extern const struct Curl_handler Curl_handler_telnet;
+#endif
+
+#endif /* HEADER_CURL_TELNET_H */
+
diff --git a/libs/libcurl/src/tftp.c b/libs/libcurl/src/tftp.c
new file mode 100644
index 0000000000..f1ffd2a3ad
--- /dev/null
+++ b/libs/libcurl/src/tftp.c
@@ -0,0 +1,1370 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#ifndef CURL_DISABLE_TFTP
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "transfer.h"
+#include "sendf.h"
+#include "tftp.h"
+#include "progress.h"
+#include "connect.h"
+#include "strerror.h"
+#include "sockaddr.h" /* required for Curl_sockaddr_storage */
+#include "multiif.h"
+#include "url.h"
+#include "rawstr.h"
+#include "speedcheck.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+#include "curl_memory.h"
+#include "select.h"
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+/* RFC2348 allows the block size to be negotiated */
+#define TFTP_BLKSIZE_DEFAULT 512
+#define TFTP_BLKSIZE_MIN 8
+#define TFTP_BLKSIZE_MAX 65464
+#define TFTP_OPTION_BLKSIZE "blksize"
+
+/* from RFC2349: */
+#define TFTP_OPTION_TSIZE "tsize"
+#define TFTP_OPTION_INTERVAL "timeout"
+
+typedef enum {
+ TFTP_MODE_NETASCII=0,
+ TFTP_MODE_OCTET
+} tftp_mode_t;
+
+typedef enum {
+ TFTP_STATE_START=0,
+ TFTP_STATE_RX,
+ TFTP_STATE_TX,
+ TFTP_STATE_FIN
+} tftp_state_t;
+
+typedef enum {
+ TFTP_EVENT_NONE = -1,
+ TFTP_EVENT_INIT = 0,
+ TFTP_EVENT_RRQ = 1,
+ TFTP_EVENT_WRQ = 2,
+ TFTP_EVENT_DATA = 3,
+ TFTP_EVENT_ACK = 4,
+ TFTP_EVENT_ERROR = 5,
+ TFTP_EVENT_OACK = 6,
+ TFTP_EVENT_TIMEOUT
+} tftp_event_t;
+
+typedef enum {
+ TFTP_ERR_UNDEF=0,
+ TFTP_ERR_NOTFOUND,
+ TFTP_ERR_PERM,
+ TFTP_ERR_DISKFULL,
+ TFTP_ERR_ILLEGAL,
+ TFTP_ERR_UNKNOWNID,
+ TFTP_ERR_EXISTS,
+ TFTP_ERR_NOSUCHUSER, /* This will never be triggered by this code */
+
+ /* The remaining error codes are internal to curl */
+ TFTP_ERR_NONE = -100,
+ TFTP_ERR_TIMEOUT,
+ TFTP_ERR_NORESPONSE
+} tftp_error_t;
+
+typedef struct tftp_packet {
+ unsigned char *data;
+} tftp_packet_t;
+
+typedef struct tftp_state_data {
+ tftp_state_t state;
+ tftp_mode_t mode;
+ tftp_error_t error;
+ tftp_event_t event;
+ struct connectdata *conn;
+ curl_socket_t sockfd;
+ int retries;
+ int retry_time;
+ int retry_max;
+ time_t start_time;
+ time_t max_time;
+ time_t rx_time;
+ unsigned short block;
+ struct Curl_sockaddr_storage local_addr;
+ struct Curl_sockaddr_storage remote_addr;
+ curl_socklen_t remote_addrlen;
+ int rbytes;
+ int sbytes;
+ int blksize;
+ int requested_blksize;
+ tftp_packet_t rpacket;
+ tftp_packet_t spacket;
+} tftp_state_data_t;
+
+
+/* Forward declarations */
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event) ;
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event) ;
+static CURLcode tftp_connect(struct connectdata *conn, bool *done);
+static CURLcode tftp_disconnect(struct connectdata *conn,
+ bool dead_connection);
+static CURLcode tftp_do(struct connectdata *conn, bool *done);
+static CURLcode tftp_done(struct connectdata *conn,
+ CURLcode, bool premature);
+static CURLcode tftp_setup_connection(struct connectdata * conn);
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done);
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done);
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks);
+static CURLcode tftp_translate_code(tftp_error_t error);
+
+
+/*
+ * TFTP protocol handler.
+ */
+
+const struct Curl_handler Curl_handler_tftp = {
+ "TFTP", /* scheme */
+ tftp_setup_connection, /* setup_connection */
+ tftp_do, /* do_it */
+ tftp_done, /* done */
+ ZERO_NULL, /* do_more */
+ tftp_connect, /* connect_it */
+ tftp_multi_statemach, /* connecting */
+ tftp_doing, /* doing */
+ tftp_getsock, /* proto_getsock */
+ tftp_getsock, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ tftp_disconnect, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ PORT_TFTP, /* defport */
+ CURLPROTO_TFTP, /* protocol */
+ PROTOPT_NONE | PROTOPT_NOURLQUERY /* flags */
+};
+
+/**********************************************************
+ *
+ * tftp_set_timeouts -
+ *
+ * Set timeouts based on state machine state.
+ * Use user provided connect timeouts until DATA or ACK
+ * packet is received, then use user-provided transfer timeouts
+ *
+ *
+ **********************************************************/
+static CURLcode tftp_set_timeouts(tftp_state_data_t *state)
+{
+ time_t maxtime, timeout;
+ long timeout_ms;
+ bool start = (state->state == TFTP_STATE_START) ? TRUE : FALSE;
+
+ time(&state->start_time);
+
+ /* Compute drop-dead time */
+ timeout_ms = Curl_timeleft(state->conn->data, NULL, start);
+
+ if(timeout_ms < 0) {
+ /* time-out, bail out, go home */
+ failf(state->conn->data, "Connection time-out");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+
+ if(start) {
+
+ maxtime = (time_t)(timeout_ms + 500) / 1000;
+ state->max_time = state->start_time+maxtime;
+
+ /* Set per-block timeout to total */
+ timeout = maxtime ;
+
+ /* Average restart after 5 seconds */
+ state->retry_max = (int)timeout/5;
+
+ if(state->retry_max < 1)
+ /* avoid division by zero below */
+ state->retry_max = 1;
+
+ /* Compute the re-start interval to suit the timeout */
+ state->retry_time = (int)timeout/state->retry_max;
+ if(state->retry_time<1)
+ state->retry_time=1;
+
+ }
+ else {
+ if(timeout_ms > 0)
+ maxtime = (time_t)(timeout_ms + 500) / 1000;
+ else
+ maxtime = 3600;
+
+ state->max_time = state->start_time+maxtime;
+
+ /* Set per-block timeout to total */
+ timeout = maxtime;
+
+ /* Average reposting an ACK after 5 seconds */
+ state->retry_max = (int)timeout/5;
+ }
+ /* But bound the total number */
+ if(state->retry_max<3)
+ state->retry_max=3;
+
+ if(state->retry_max>50)
+ state->retry_max=50;
+
+ /* Compute the re-ACK interval to suit the timeout */
+ state->retry_time = (int)(timeout/state->retry_max);
+ if(state->retry_time<1)
+ state->retry_time=1;
+
+ infof(state->conn->data,
+ "set timeouts for state %d; Total %ld, retry %d maxtry %d\n",
+ (int)state->state, (long)(state->max_time-state->start_time),
+ state->retry_time, state->retry_max);
+
+ /* init RX time */
+ time(&state->rx_time);
+
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_set_send_first
+ *
+ * Event handler for the START state
+ *
+ **********************************************************/
+
+static void setpacketevent(tftp_packet_t *packet, unsigned short num)
+{
+ packet->data[0] = (unsigned char)(num >> 8);
+ packet->data[1] = (unsigned char)(num & 0xff);
+}
+
+
+static void setpacketblock(tftp_packet_t *packet, unsigned short num)
+{
+ packet->data[2] = (unsigned char)(num >> 8);
+ packet->data[3] = (unsigned char)(num & 0xff);
+}
+
+static unsigned short getrpacketevent(const tftp_packet_t *packet)
+{
+ return (unsigned short)((packet->data[0] << 8) | packet->data[1]);
+}
+
+static unsigned short getrpacketblock(const tftp_packet_t *packet)
+{
+ return (unsigned short)((packet->data[2] << 8) | packet->data[3]);
+}
+
+static size_t Curl_strnlen(const char *string, size_t maxlen)
+{
+ const char *end = memchr (string, '\0', maxlen);
+ return end ? (size_t) (end - string) : maxlen;
+}
+
+static const char *tftp_option_get(const char *buf, size_t len,
+ const char **option, const char **value)
+{
+ size_t loc;
+
+ loc = Curl_strnlen( buf, len );
+ loc++; /* NULL term */
+
+ if(loc >= len)
+ return NULL;
+ *option = buf;
+
+ loc += Curl_strnlen( buf+loc, len-loc );
+ loc++; /* NULL term */
+
+ if(loc > len)
+ return NULL;
+ *value = &buf[strlen(*option) + 1];
+
+ return &buf[loc];
+}
+
+static CURLcode tftp_parse_option_ack(tftp_state_data_t *state,
+ const char *ptr, int len)
+{
+ const char *tmp = ptr;
+ struct SessionHandle *data = state->conn->data;
+
+ /* if OACK doesn't contain blksize option, the default (512) must be used */
+ state->blksize = TFTP_BLKSIZE_DEFAULT;
+
+ while(tmp < ptr + len) {
+ const char *option, *value;
+
+ tmp = tftp_option_get(tmp, ptr + len - tmp, &option, &value);
+ if(tmp == NULL) {
+ failf(data, "Malformed ACK packet, rejecting");
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ infof(data, "got option=(%s) value=(%s)\n", option, value);
+
+ if(checkprefix(option, TFTP_OPTION_BLKSIZE)) {
+ long blksize;
+
+ blksize = strtol( value, NULL, 10 );
+
+ if(!blksize) {
+ failf(data, "invalid blocksize value in OACK packet");
+ return CURLE_TFTP_ILLEGAL;
+ }
+ else if(blksize > TFTP_BLKSIZE_MAX) {
+ failf(data, "%s (%d)", "blksize is larger than max supported",
+ TFTP_BLKSIZE_MAX);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ else if(blksize < TFTP_BLKSIZE_MIN) {
+ failf(data, "%s (%d)", "blksize is smaller than min supported",
+ TFTP_BLKSIZE_MIN);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ else if(blksize > state->requested_blksize) {
+ /* could realloc pkt buffers here, but the spec doesn't call out
+ * support for the server requesting a bigger blksize than the client
+ * requests */
+ failf(data, "%s (%ld)",
+ "server requested blksize larger than allocated", blksize);
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ state->blksize = (int)blksize;
+ infof(data, "%s (%d) %s (%d)\n", "blksize parsed from OACK",
+ state->blksize, "requested", state->requested_blksize);
+ }
+ else if(checkprefix(option, TFTP_OPTION_TSIZE)) {
+ long tsize = 0;
+
+ tsize = strtol( value, NULL, 10 );
+ infof(data, "%s (%ld)\n", "tsize parsed from OACK", tsize);
+
+ /* tsize should be ignored on upload: Who cares about the size of the
+ remote file? */
+ if(!data->set.upload) {
+ if(!tsize) {
+ failf(data, "invalid tsize -:%s:- value in OACK packet", value);
+ return CURLE_TFTP_ILLEGAL;
+ }
+ Curl_pgrsSetDownloadSize(data, tsize);
+ }
+ }
+ }
+
+ return CURLE_OK;
+}
+
+static size_t tftp_option_add(tftp_state_data_t *state, size_t csize,
+ char *buf, const char *option)
+{
+ if(( strlen(option) + csize + 1 ) > (size_t)state->blksize)
+ return 0;
+ strcpy(buf, option);
+ return( strlen(option) + 1 );
+}
+
+static CURLcode tftp_connect_for_tx(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode res;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ struct SessionHandle *data = state->conn->data;
+
+ infof(data, "%s\n", "Connected for transmit");
+#endif
+ state->state = TFTP_STATE_TX;
+ res = tftp_set_timeouts(state);
+ if(res != CURLE_OK)
+ return(res);
+ return tftp_tx(state, event);
+}
+
+static CURLcode tftp_connect_for_rx(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode res;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ struct SessionHandle *data = state->conn->data;
+
+ infof(data, "%s\n", "Connected for receive");
+#endif
+ state->state = TFTP_STATE_RX;
+ res = tftp_set_timeouts(state);
+ if(res != CURLE_OK)
+ return(res);
+ return tftp_rx(state, event);
+}
+
+static CURLcode tftp_send_first(tftp_state_data_t *state, tftp_event_t event)
+{
+ size_t sbytes;
+ ssize_t senddata;
+ const char *mode = "octet";
+ char *filename;
+ char buf[64];
+ struct SessionHandle *data = state->conn->data;
+ CURLcode res = CURLE_OK;
+
+ /* Set ascii mode if -B flag was used */
+ if(data->set.prefer_ascii)
+ mode = "netascii";
+
+ switch(event) {
+
+ case TFTP_EVENT_INIT: /* Send the first packet out */
+ case TFTP_EVENT_TIMEOUT: /* Resend the first packet out */
+ /* Increment the retry counter, quit if over the limit */
+ state->retries++;
+ if(state->retries>state->retry_max) {
+ state->error = TFTP_ERR_NORESPONSE;
+ state->state = TFTP_STATE_FIN;
+ return res;
+ }
+
+ if(data->set.upload) {
+ /* If we are uploading, send an WRQ */
+ setpacketevent(&state->spacket, TFTP_EVENT_WRQ);
+ state->conn->data->req.upload_fromhere =
+ (char *)state->spacket.data+4;
+ if(data->set.infilesize != -1)
+ Curl_pgrsSetUploadSize(data, data->set.infilesize);
+ }
+ else {
+ /* If we are downloading, send an RRQ */
+ setpacketevent(&state->spacket, TFTP_EVENT_RRQ);
+ }
+ /* As RFC3617 describes the separator slash is not actually part of the
+ file name so we skip the always-present first letter of the path
+ string. */
+ filename = curl_easy_unescape(data, &state->conn->data->state.path[1], 0,
+ NULL);
+ if(!filename)
+ return CURLE_OUT_OF_MEMORY;
+
+ snprintf((char *)state->spacket.data+2,
+ state->blksize,
+ "%s%c%s%c", filename, '\0', mode, '\0');
+ sbytes = 4 + strlen(filename) + strlen(mode);
+
+ /* add tsize option */
+ if(data->set.upload && (data->set.infilesize != -1))
+ snprintf( buf, sizeof(buf), "%" FORMAT_OFF_T, data->set.infilesize );
+ else
+ strcpy(buf, "0"); /* the destination is large enough */
+
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_TSIZE);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf);
+ /* add blksize option */
+ snprintf( buf, sizeof(buf), "%d", state->requested_blksize );
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_BLKSIZE);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf );
+
+ /* add timeout option */
+ snprintf( buf, sizeof(buf), "%d", state->retry_time);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes,
+ TFTP_OPTION_INTERVAL);
+ sbytes += tftp_option_add(state, sbytes,
+ (char *)state->spacket.data+sbytes, buf );
+
+ /* the typecase for the 3rd argument is mostly for systems that do
+ not have a size_t argument, like older unixes that want an 'int' */
+ senddata = sendto(state->sockfd, (void *)state->spacket.data,
+ (SEND_TYPE_ARG3)sbytes, 0,
+ state->conn->ip_addr->ai_addr,
+ state->conn->ip_addr->ai_addrlen);
+ if(senddata != (ssize_t)sbytes) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ }
+ Curl_safefree(filename);
+ break;
+
+ case TFTP_EVENT_OACK:
+ if(data->set.upload) {
+ res = tftp_connect_for_tx(state, event);
+ }
+ else {
+ res = tftp_connect_for_rx(state, event);
+ }
+ break;
+
+ case TFTP_EVENT_ACK: /* Connected for transmit */
+ res = tftp_connect_for_tx(state, event);
+ break;
+
+ case TFTP_EVENT_DATA: /* Connected for receive */
+ res = tftp_connect_for_rx(state, event);
+ break;
+
+ case TFTP_EVENT_ERROR:
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(state->conn->data, "tftp_send_first: internal error");
+ break;
+ }
+ return res;
+}
+
+/* the next blocknum is x + 1 but it needs to wrap at an unsigned 16bit
+ boundary */
+#define NEXT_BLOCKNUM(x) (((x)+1)&0xffff)
+
+/**********************************************************
+ *
+ * tftp_rx
+ *
+ * Event handler for the RX state
+ *
+ **********************************************************/
+static CURLcode tftp_rx(tftp_state_data_t *state, tftp_event_t event)
+{
+ ssize_t sbytes;
+ int rblock;
+ struct SessionHandle *data = state->conn->data;
+
+ switch(event) {
+
+ case TFTP_EVENT_DATA:
+ /* Is this the block we expect? */
+ rblock = getrpacketblock(&state->rpacket);
+ if(NEXT_BLOCKNUM(state->block) == rblock) {
+ /* This is the expected block. Reset counters and ACK it. */
+ state->retries = 0;
+ }
+ else if(state->block == rblock) {
+ /* This is the last recently received block again. Log it and ACK it
+ again. */
+ infof(data, "Received last DATA packet block %d again.\n", rblock);
+ }
+ else {
+ /* totally unexpected, just log it */
+ infof(data,
+ "Received unexpected DATA packet block %d, expecting block %d\n",
+ rblock, NEXT_BLOCKNUM(state->block));
+ break;
+ }
+
+ /* ACK this block. */
+ state->block = (unsigned short)rblock;
+ setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+ setpacketblock(&state->spacket, state->block);
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes < 0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+
+ /* Check if completed (That is, a less than full packet is received) */
+ if(state->rbytes < (ssize_t)state->blksize+4) {
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ state->state = TFTP_STATE_RX;
+ }
+ time(&state->rx_time);
+ break;
+
+ case TFTP_EVENT_OACK:
+ /* ACK option acknowledgement so we can move on to data */
+ state->block = 0;
+ state->retries = 0;
+ setpacketevent(&state->spacket, TFTP_EVENT_ACK);
+ setpacketblock(&state->spacket, state->block);
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes < 0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+
+ /* we're ready to RX data */
+ state->state = TFTP_STATE_RX;
+ time(&state->rx_time);
+ break;
+
+ case TFTP_EVENT_TIMEOUT:
+ /* Increment the retry count and fail if over the limit */
+ state->retries++;
+ infof(data,
+ "Timeout waiting for block %d ACK. Retries = %d\n",
+ NEXT_BLOCKNUM(state->block), state->retries);
+ if(state->retries > state->retry_max) {
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ /* Resend the previous ACK */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ }
+ break;
+
+ case TFTP_EVENT_ERROR:
+ setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+ setpacketblock(&state->spacket, state->block);
+ (void)sendto(state->sockfd, (void *)state->spacket.data,
+ 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(data, "%s", "tftp_rx: internal error");
+ return CURLE_TFTP_ILLEGAL; /* not really the perfect return code for
+ this */
+ }
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_tx
+ *
+ * Event handler for the TX state
+ *
+ **********************************************************/
+static CURLcode tftp_tx(tftp_state_data_t *state, tftp_event_t event)
+{
+ struct SessionHandle *data = state->conn->data;
+ ssize_t sbytes;
+ int rblock;
+ CURLcode res = CURLE_OK;
+ struct SingleRequest *k = &data->req;
+
+ switch(event) {
+
+ case TFTP_EVENT_ACK:
+ case TFTP_EVENT_OACK:
+ if(event == TFTP_EVENT_ACK) {
+ /* Ack the packet */
+ rblock = getrpacketblock(&state->rpacket);
+
+ if(rblock != state->block &&
+ /* There's a bug in tftpd-hpa that causes it to send us an ack for
+ * 65535 when the block number wraps to 0. So when we're expecting
+ * 0, also accept 65535. See
+ * http://syslinux.zytor.com/archives/2010-September/015253.html
+ * */
+ !(state->block == 0 && rblock == 65535)) {
+ /* This isn't the expected block. Log it and up the retry counter */
+ infof(data, "Received ACK for block %d, expecting %d\n",
+ rblock, state->block);
+ state->retries++;
+ /* Bail out if over the maximum */
+ if(state->retries>state->retry_max) {
+ failf(data, "tftp_tx: giving up waiting for block %d ack",
+ state->block);
+ res = CURLE_SEND_ERROR;
+ }
+ else {
+ /* Re-send the data packet */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4+state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ res = CURLE_SEND_ERROR;
+ }
+ }
+ return res;
+ }
+ /* This is the expected packet. Reset the counters and send the next
+ block */
+ time(&state->rx_time);
+ state->block++;
+ }
+ else
+ state->block = 1; /* first data block is 1 when using OACK */
+
+ state->retries = 0;
+ setpacketevent(&state->spacket, TFTP_EVENT_DATA);
+ setpacketblock(&state->spacket, state->block);
+ if(state->block > 1 && state->sbytes < (int)state->blksize) {
+ state->state = TFTP_STATE_FIN;
+ return CURLE_OK;
+ }
+ res = Curl_fillreadbuffer(state->conn, state->blksize, &state->sbytes);
+ if(res)
+ return res;
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4+state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ /* Update the progress meter */
+ k->writebytecount += state->sbytes;
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+ break;
+
+ case TFTP_EVENT_TIMEOUT:
+ /* Increment the retry counter and log the timeout */
+ state->retries++;
+ infof(data, "Timeout waiting for block %d ACK. "
+ " Retries = %d\n", NEXT_BLOCKNUM(state->block), state->retries);
+ /* Decide if we've had enough */
+ if(state->retries > state->retry_max) {
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ }
+ else {
+ /* Re-send the data packet */
+ sbytes = sendto(state->sockfd, (void *)state->spacket.data,
+ 4+state->sbytes, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* Check all sbytes were sent */
+ if(sbytes<0) {
+ failf(data, "%s", Curl_strerror(state->conn, SOCKERRNO));
+ return CURLE_SEND_ERROR;
+ }
+ /* since this was a re-send, we remain at the still byte position */
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+ }
+ break;
+
+ case TFTP_EVENT_ERROR:
+ state->state = TFTP_STATE_FIN;
+ setpacketevent(&state->spacket, TFTP_EVENT_ERROR);
+ setpacketblock(&state->spacket, state->block);
+ (void)sendto(state->sockfd, (void *)state->spacket.data, 4, SEND_4TH_ARG,
+ (struct sockaddr *)&state->remote_addr,
+ state->remote_addrlen);
+ /* don't bother with the return code, but if the socket is still up we
+ * should be a good TFTP client and let the server know we're done */
+ state->state = TFTP_STATE_FIN;
+ break;
+
+ default:
+ failf(data, "tftp_tx: internal error, event: %i", (int)(event));
+ break;
+ }
+
+ return res;
+}
+
+/**********************************************************
+ *
+ * tftp_translate_code
+ *
+ * Translate internal error codes to CURL error codes
+ *
+ **********************************************************/
+static CURLcode tftp_translate_code(tftp_error_t error)
+{
+ CURLcode code = CURLE_OK;
+
+ if(error != TFTP_ERR_NONE) {
+ switch(error) {
+ case TFTP_ERR_NOTFOUND:
+ code = CURLE_TFTP_NOTFOUND;
+ break;
+ case TFTP_ERR_PERM:
+ code = CURLE_TFTP_PERM;
+ break;
+ case TFTP_ERR_DISKFULL:
+ code = CURLE_REMOTE_DISK_FULL;
+ break;
+ case TFTP_ERR_UNDEF:
+ case TFTP_ERR_ILLEGAL:
+ code = CURLE_TFTP_ILLEGAL;
+ break;
+ case TFTP_ERR_UNKNOWNID:
+ code = CURLE_TFTP_UNKNOWNID;
+ break;
+ case TFTP_ERR_EXISTS:
+ code = CURLE_REMOTE_FILE_EXISTS;
+ break;
+ case TFTP_ERR_NOSUCHUSER:
+ code = CURLE_TFTP_NOSUCHUSER;
+ break;
+ case TFTP_ERR_TIMEOUT:
+ code = CURLE_OPERATION_TIMEDOUT;
+ break;
+ case TFTP_ERR_NORESPONSE:
+ code = CURLE_COULDNT_CONNECT;
+ break;
+ default:
+ code= CURLE_ABORTED_BY_CALLBACK;
+ break;
+ }
+ }
+ else {
+ code = CURLE_OK;
+ }
+
+ return(code);
+}
+
+/**********************************************************
+ *
+ * tftp_state_machine
+ *
+ * The tftp state machine event dispatcher
+ *
+ **********************************************************/
+static CURLcode tftp_state_machine(tftp_state_data_t *state,
+ tftp_event_t event)
+{
+ CURLcode res = CURLE_OK;
+ struct SessionHandle *data = state->conn->data;
+ switch(state->state) {
+ case TFTP_STATE_START:
+ DEBUGF(infof(data, "TFTP_STATE_START\n"));
+ res = tftp_send_first(state, event);
+ break;
+ case TFTP_STATE_RX:
+ DEBUGF(infof(data, "TFTP_STATE_RX\n"));
+ res = tftp_rx(state, event);
+ break;
+ case TFTP_STATE_TX:
+ DEBUGF(infof(data, "TFTP_STATE_TX\n"));
+ res = tftp_tx(state, event);
+ break;
+ case TFTP_STATE_FIN:
+ infof(data, "%s\n", "TFTP finished");
+ break;
+ default:
+ DEBUGF(infof(data, "STATE: %d\n", state->state));
+ failf(data, "%s", "Internal state machine error");
+ res = CURLE_TFTP_ILLEGAL;
+ break;
+ }
+ return res;
+}
+
+/**********************************************************
+ *
+ * tftp_disconnect
+ *
+ * The disconnect callback
+ *
+ **********************************************************/
+static CURLcode tftp_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ tftp_state_data_t *state = conn->proto.tftpc;
+ (void) dead_connection;
+
+ /* done, free dynamically allocated pkt buffers */
+ if(state) {
+ Curl_safefree(state->rpacket.data);
+ Curl_safefree(state->spacket.data);
+ free(state);
+ }
+
+ return CURLE_OK;
+}
+
+/**********************************************************
+ *
+ * tftp_connect
+ *
+ * The connect callback
+ *
+ **********************************************************/
+static CURLcode tftp_connect(struct connectdata *conn, bool *done)
+{
+ CURLcode code;
+ tftp_state_data_t *state;
+ int blksize, rc;
+
+ blksize = TFTP_BLKSIZE_DEFAULT;
+
+ state = conn->proto.tftpc = calloc(1, sizeof(tftp_state_data_t));
+ if(!state)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* alloc pkt buffers based on specified blksize */
+ if(conn->data->set.tftp_blksize) {
+ blksize = (int)conn->data->set.tftp_blksize;
+ if(blksize > TFTP_BLKSIZE_MAX || blksize < TFTP_BLKSIZE_MIN )
+ return CURLE_TFTP_ILLEGAL;
+ }
+
+ if(!state->rpacket.data) {
+ state->rpacket.data = calloc(1, blksize + 2 + 2);
+
+ if(!state->rpacket.data)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!state->spacket.data) {
+ state->spacket.data = calloc(1, blksize + 2 + 2);
+
+ if(!state->spacket.data)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ conn->bits.close = TRUE; /* we don't keep TFTP connections up bascially
+ because there's none or very little gain for UDP
+ */
+
+ state->conn = conn;
+ state->sockfd = state->conn->sock[FIRSTSOCKET];
+ state->state = TFTP_STATE_START;
+ state->error = TFTP_ERR_NONE;
+ state->blksize = TFTP_BLKSIZE_DEFAULT;
+ state->requested_blksize = blksize;
+
+ ((struct sockaddr *)&state->local_addr)->sa_family =
+ (unsigned short)(conn->ip_addr->ai_family);
+
+ tftp_set_timeouts(state);
+
+ if(!conn->bits.bound) {
+ /* If not already bound, bind to any interface, random UDP port. If it is
+ * reused or a custom local port was desired, this has already been done!
+ *
+ * We once used the size of the local_addr struct as the third argument
+ * for bind() to better work with IPv6 or whatever size the struct could
+ * have, but we learned that at least Tru64, AIX and IRIX *requires* the
+ * size of that argument to match the exact size of a 'sockaddr_in' struct
+ * when running IPv4-only.
+ *
+ * Therefore we use the size from the address we connected to, which we
+ * assume uses the same IP version and thus hopefully this works for both
+ * IPv4 and IPv6...
+ */
+ rc = bind(state->sockfd, (struct sockaddr *)&state->local_addr,
+ conn->ip_addr->ai_addrlen);
+ if(rc) {
+ failf(conn->data, "bind() failed; %s",
+ Curl_strerror(conn, SOCKERRNO));
+ return CURLE_COULDNT_CONNECT;
+ }
+ conn->bits.bound = TRUE;
+ }
+
+ Curl_pgrsStartNow(conn->data);
+
+ *done = TRUE;
+ code = CURLE_OK;
+ return(code);
+}
+
+/**********************************************************
+ *
+ * tftp_done
+ *
+ * The done callback
+ *
+ **********************************************************/
+static CURLcode tftp_done(struct connectdata *conn, CURLcode status,
+ bool premature)
+{
+ CURLcode code = CURLE_OK;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ (void)status; /* unused */
+ (void)premature; /* not used */
+
+ if(Curl_pgrsDone(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+
+ /* If we have encountered an error */
+ code = tftp_translate_code(state->error);
+
+ return code;
+}
+
+/**********************************************************
+ *
+ * tftp_getsock
+ *
+ * The getsock callback
+ *
+ **********************************************************/
+static int tftp_getsock(struct connectdata *conn, curl_socket_t *socks,
+ int numsocks)
+{
+ if(!numsocks)
+ return GETSOCK_BLANK;
+
+ socks[0] = conn->sock[FIRSTSOCKET];
+
+ return GETSOCK_READSOCK(0);
+}
+
+/**********************************************************
+ *
+ * tftp_receive_packet
+ *
+ * Called once select fires and data is ready on the socket
+ *
+ **********************************************************/
+static CURLcode tftp_receive_packet(struct connectdata *conn)
+{
+ struct Curl_sockaddr_storage fromaddr;
+ curl_socklen_t fromlen;
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ struct SingleRequest *k = &data->req;
+
+ /* Receive the packet */
+ fromlen = sizeof(fromaddr);
+ state->rbytes = (int)recvfrom(state->sockfd,
+ (void *)state->rpacket.data,
+ state->blksize+4,
+ 0,
+ (struct sockaddr *)&fromaddr,
+ &fromlen);
+ if(state->remote_addrlen==0) {
+ memcpy(&state->remote_addr, &fromaddr, fromlen);
+ state->remote_addrlen = fromlen;
+ }
+
+ /* Sanity check packet length */
+ if(state->rbytes < 4) {
+ failf(data, "Received too short packet");
+ /* Not a timeout, but how best to handle it? */
+ state->event = TFTP_EVENT_TIMEOUT;
+ }
+ else {
+ /* The event is given by the TFTP packet time */
+ state->event = (tftp_event_t)getrpacketevent(&state->rpacket);
+
+ switch(state->event) {
+ case TFTP_EVENT_DATA:
+ /* Don't pass to the client empty or retransmitted packets */
+ if(state->rbytes > 4 &&
+ (NEXT_BLOCKNUM(state->block) == getrpacketblock(&state->rpacket))) {
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ (char *)state->rpacket.data+4,
+ state->rbytes-4);
+ if(result) {
+ tftp_state_machine(state, TFTP_EVENT_ERROR);
+ return result;
+ }
+ k->bytecount += state->rbytes-4;
+ Curl_pgrsSetDownloadCounter(data, (curl_off_t) k->bytecount);
+ }
+ break;
+ case TFTP_EVENT_ERROR:
+ state->error = (tftp_error_t)getrpacketblock(&state->rpacket);
+ infof(data, "%s\n", (const char *)state->rpacket.data+4);
+ break;
+ case TFTP_EVENT_ACK:
+ break;
+ case TFTP_EVENT_OACK:
+ result = tftp_parse_option_ack(state,
+ (const char *)state->rpacket.data+2,
+ state->rbytes-2);
+ if(result)
+ return result;
+ break;
+ case TFTP_EVENT_RRQ:
+ case TFTP_EVENT_WRQ:
+ default:
+ failf(data, "%s", "Internal error: Unexpected packet");
+ break;
+ }
+
+ /* Update the progress meter */
+ if(Curl_pgrsUpdate(conn)) {
+ tftp_state_machine(state, TFTP_EVENT_ERROR);
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ }
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_state_timeout
+ *
+ * Check if timeouts have been reached
+ *
+ **********************************************************/
+static long tftp_state_timeout(struct connectdata *conn, tftp_event_t *event)
+{
+ time_t current;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ if(event)
+ *event = TFTP_EVENT_NONE;
+
+ time(&current);
+ if(current > state->max_time) {
+ DEBUGF(infof(conn->data, "timeout: %ld > %ld\n",
+ (long)current, (long)state->max_time));
+ state->error = TFTP_ERR_TIMEOUT;
+ state->state = TFTP_STATE_FIN;
+ return 0;
+ }
+ else if(current > state->rx_time+state->retry_time) {
+ if(event)
+ *event = TFTP_EVENT_TIMEOUT;
+ time(&state->rx_time); /* update even though we received nothing */
+ }
+
+ /* there's a typecast below here since 'time_t' may in fact be larger than
+ 'long', but we estimate that a 'long' will still be able to hold number
+ of seconds even if "only" 32 bit */
+ return (long)(state->max_time - current);
+}
+
+/**********************************************************
+ *
+ * tftp_multi_statemach
+ *
+ * Handle single RX socket event and return
+ *
+ **********************************************************/
+static CURLcode tftp_multi_statemach(struct connectdata *conn, bool *done)
+{
+ int rc;
+ tftp_event_t event;
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+ long timeout_ms = tftp_state_timeout(conn, &event);
+
+ *done = FALSE;
+
+ if(timeout_ms <= 0) {
+ failf(data, "TFTP response timeout");
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ else if(event != TFTP_EVENT_NONE) {
+ result = tftp_state_machine(state, event);
+ if(result != CURLE_OK)
+ return(result);
+ *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+ if(*done)
+ /* Tell curl we're done */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ }
+ else {
+ /* no timeouts to handle, check our socket */
+ rc = Curl_socket_ready(state->sockfd, CURL_SOCKET_BAD, 0);
+
+ if(rc == -1) {
+ /* bail out */
+ int error = SOCKERRNO;
+ failf(data, "%s", Curl_strerror(conn, error));
+ state->event = TFTP_EVENT_ERROR;
+ }
+ else if(rc != 0) {
+ result = tftp_receive_packet(conn);
+ if(result != CURLE_OK)
+ return(result);
+ result = tftp_state_machine(state, state->event);
+ if(result != CURLE_OK)
+ return(result);
+ *done = (state->state == TFTP_STATE_FIN) ? TRUE : FALSE;
+ if(*done)
+ /* Tell curl we're done */
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
+ }
+ /* if rc == 0, then select() timed out */
+ }
+
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_doing
+ *
+ * Called from multi.c while DOing
+ *
+ **********************************************************/
+static CURLcode tftp_doing(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result;
+ result = tftp_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done) {
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+ }
+ else {
+ /* The multi code doesn't have this logic for the DOING state so we
+ provide it for TFTP since it may do the entire transfer in this
+ state. */
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(conn->data, Curl_tvnow());
+ }
+ return result;
+}
+
+/**********************************************************
+ *
+ * tftp_peform
+ *
+ * Entry point for transfer from tftp_do, sarts state mach
+ *
+ **********************************************************/
+static CURLcode tftp_perform(struct connectdata *conn, bool *dophase_done)
+{
+ CURLcode result = CURLE_OK;
+ tftp_state_data_t *state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ *dophase_done = FALSE;
+
+ result = tftp_state_machine(state, TFTP_EVENT_INIT);
+
+ if(state->state == TFTP_STATE_FIN || result != CURLE_OK)
+ return(result);
+
+ tftp_multi_statemach(conn, dophase_done);
+
+ if(*dophase_done)
+ DEBUGF(infof(conn->data, "DO phase is complete\n"));
+
+ return result;
+}
+
+
+/**********************************************************
+ *
+ * tftp_do
+ *
+ * The do callback
+ *
+ * This callback initiates the TFTP transfer
+ *
+ **********************************************************/
+
+static CURLcode tftp_do(struct connectdata *conn, bool *done)
+{
+ tftp_state_data_t *state;
+ CURLcode code;
+
+ *done = FALSE;
+
+ if(!conn->proto.tftpc) {
+ code = tftp_connect(conn, done);
+ if(code)
+ return code;
+ }
+ state = (tftp_state_data_t *)conn->proto.tftpc;
+
+ code = tftp_perform(conn, done);
+
+ /* If tftp_perform() returned an error, use that for return code. If it
+ was OK, see if tftp_translate_code() has an error. */
+ if(code == CURLE_OK)
+ /* If we have encountered an internal tftp error, translate it. */
+ code = tftp_translate_code(state->error);
+
+ return code;
+}
+
+static CURLcode tftp_setup_connection(struct connectdata * conn)
+{
+ struct SessionHandle *data = conn->data;
+ char * type;
+ char command;
+
+ conn->socktype = SOCK_DGRAM; /* UDP datagram based */
+
+ /* TFTP URLs support an extension like ";mode=<typecode>" that
+ * we'll try to get now! */
+ type = strstr(data->state.path, ";mode=");
+
+ if(!type)
+ type = strstr(conn->host.rawalloc, ";mode=");
+
+ if(type) {
+ *type = 0; /* it was in the middle of the hostname */
+ command = Curl_raw_toupper(type[6]);
+
+ switch (command) {
+ case 'A': /* ASCII mode */
+ case 'N': /* NETASCII mode */
+ data->set.prefer_ascii = TRUE;
+ break;
+
+ case 'O': /* octet mode */
+ case 'I': /* binary mode */
+ default:
+ /* switch off ASCII */
+ data->set.prefer_ascii = FALSE;
+ break;
+ }
+ }
+
+ return CURLE_OK;
+}
+#endif
diff --git a/libs/libcurl/src/tftp.h b/libs/libcurl/src/tftp.h
new file mode 100644
index 0000000000..117b40f62d
--- /dev/null
+++ b/libs/libcurl/src/tftp.h
@@ -0,0 +1,29 @@
+#ifndef HEADER_CURL_TFTP_H
+#define HEADER_CURL_TFTP_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+#ifndef CURL_DISABLE_TFTP
+extern const struct Curl_handler Curl_handler_tftp;
+#endif
+
+#endif /* HEADER_CURL_TFTP_H */
+
diff --git a/libs/libcurl/src/timeval.c b/libs/libcurl/src/timeval.c
new file mode 100644
index 0000000000..2fd7201448
--- /dev/null
+++ b/libs/libcurl/src/timeval.c
@@ -0,0 +1,134 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2008, 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 "timeval.h"
+
+#if defined(WIN32) && !defined(MSDOS)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** GetTickCount() is available on _all_ Windows versions from W95 up
+ ** to nowadays. Returns milliseconds elapsed since last system boot,
+ ** increases monotonically and wraps once 49.7 days have elapsed.
+ */
+ struct timeval now;
+ DWORD milliseconds = GetTickCount();
+ now.tv_sec = milliseconds / 1000;
+ now.tv_usec = (milliseconds % 1000) * 1000;
+ return now;
+}
+
+#elif defined(HAVE_CLOCK_GETTIME_MONOTONIC)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** clock_gettime() is granted to be increased monotonically when the
+ ** monotonic clock is queried. Time starting point is unspecified, it
+ ** could be the system start-up time, the Epoch, or something else,
+ ** in any case the time starting point does not change once that the
+ ** system has started up.
+ */
+ struct timeval now;
+ struct timespec tsnow;
+ if(0 == clock_gettime(CLOCK_MONOTONIC, &tsnow)) {
+ now.tv_sec = tsnow.tv_sec;
+ now.tv_usec = tsnow.tv_nsec / 1000;
+ }
+ /*
+ ** Even when the configure process has truly detected monotonic clock
+ ** availability, it might happen that it is not actually available at
+ ** run-time. When this occurs simply fallback to other time source.
+ */
+#ifdef HAVE_GETTIMEOFDAY
+ else
+ (void)gettimeofday(&now, NULL);
+#else
+ else {
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ }
+#endif
+ return now;
+}
+
+#elif defined(HAVE_GETTIMEOFDAY)
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** gettimeofday() is not granted to be increased monotonically, due to
+ ** clock drifting and external source time synchronization it can jump
+ ** forward or backward in time.
+ */
+ struct timeval now;
+ (void)gettimeofday(&now, NULL);
+ return now;
+}
+
+#else
+
+struct timeval curlx_tvnow(void)
+{
+ /*
+ ** time() returns the value of time in seconds since the Epoch.
+ */
+ struct timeval now;
+ now.tv_sec = (long)time(NULL);
+ now.tv_usec = 0;
+ return now;
+}
+
+#endif
+
+/*
+ * Make sure that the first argument is the more recent time, as otherwise
+ * we'll get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long curlx_tvdiff(struct timeval newer, struct timeval older)
+{
+ return (newer.tv_sec-older.tv_sec)*1000+
+ (newer.tv_usec-older.tv_usec)/1000;
+}
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval newer, struct timeval older)
+{
+ if(newer.tv_sec != older.tv_sec)
+ return (double)(newer.tv_sec-older.tv_sec)+
+ (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+ else
+ return (double)(newer.tv_usec-older.tv_usec)/1000000.0;
+}
+
+/* return the number of seconds in the given input timeval struct */
+long Curl_tvlong(struct timeval t1)
+{
+ return t1.tv_sec;
+}
diff --git a/libs/libcurl/src/timeval.h b/libs/libcurl/src/timeval.h
new file mode 100644
index 0000000000..3f1b9ea70d
--- /dev/null
+++ b/libs/libcurl/src/timeval.h
@@ -0,0 +1,58 @@
+#ifndef HEADER_CURL_TIMEVAL_H
+#define HEADER_CURL_TIMEVAL_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2007, 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.
+ *
+ ***************************************************************************/
+
+/*
+ * CAUTION: this header is designed to work when included by the app-side
+ * as well as the library. Do not mix with library internals!
+ */
+
+#include "curl_setup.h"
+
+struct timeval curlx_tvnow(void);
+
+/*
+ * Make sure that the first argument (t1) is the more recent time and t2 is
+ * the older time, as otherwise you get a weird negative time-diff back...
+ *
+ * Returns: the time difference in number of milliseconds.
+ */
+long curlx_tvdiff(struct timeval t1, struct timeval t2);
+
+/*
+ * Same as curlx_tvdiff but with full usec resolution.
+ *
+ * Returns: the time difference in seconds with subsecond resolution.
+ */
+double curlx_tvdiff_secs(struct timeval t1, struct timeval t2);
+
+long Curl_tvlong(struct timeval t1);
+
+/* These two defines below exist to provide the older API for library
+ internals only. */
+#define Curl_tvnow() curlx_tvnow()
+#define Curl_tvdiff(x,y) curlx_tvdiff(x,y)
+#define Curl_tvdiff_secs(x,y) curlx_tvdiff_secs(x,y)
+
+#endif /* HEADER_CURL_TIMEVAL_H */
+
diff --git a/libs/libcurl/src/transfer.c b/libs/libcurl/src/transfer.c
new file mode 100644
index 0000000000..533e394b6b
--- /dev/null
+++ b/libs/libcurl/src/transfer.c
@@ -0,0 +1,1976 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 "strtoofft.h"
+#include "strequal.h"
+#include "rawstr.h"
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+#ifdef HAVE_SIGNAL_H
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef HAVE_SYS_SELECT_H
+#include <sys/select.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#include "urldata.h"
+#include <curl/curl.h>
+#include "netrc.h"
+
+#include "content_encoding.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "speedcheck.h"
+#include "progress.h"
+#include "http.h"
+#include "url.h"
+#include "getinfo.h"
+#include "sslgen.h"
+#include "http_digest.h"
+#include "curl_ntlm.h"
+#include "http_negotiate.h"
+#include "share.h"
+#include "curl_memory.h"
+#include "select.h"
+#include "multiif.h"
+#include "connect.h"
+#include "non-ascii.h"
+
+#define _MPRINTF_REPLACE /* use our functions only */
+#include <curl/mprintf.h>
+
+/* The last #include file should be: */
+#include "memdebug.h"
+
+#define CURL_TIMEOUT_EXPECT_100 1000 /* counting ms here */
+
+/*
+ * This function will call the read callback to fill our buffer with data
+ * to upload.
+ */
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp)
+{
+ struct SessionHandle *data = conn->data;
+ size_t buffersize = (size_t)bytes;
+ int nread;
+#ifdef CURL_DOES_CONVERSIONS
+ bool sending_http_headers = FALSE;
+
+ if(conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_RTSP)) {
+ const struct HTTP *http = data->req.protop;
+
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+ Remember that so we don't re-translate them into garbage. */
+ sending_http_headers = TRUE;
+ }
+#endif
+
+ if(data->req.upload_chunky) {
+ /* if chunked Transfer-Encoding */
+ buffersize -= (8 + 2 + 2); /* 32bit hex + CRLF + CRLF */
+ data->req.upload_fromhere += (8 + 2); /* 32bit hex + CRLF */
+ }
+
+ /* this function returns a size_t, so we typecast to int to prevent warnings
+ with picky compilers */
+ nread = (int)conn->fread_func(data->req.upload_fromhere, 1,
+ buffersize, conn->fread_in);
+
+ if(nread == CURL_READFUNC_ABORT) {
+ failf(data, "operation aborted by callback");
+ *nreadp = 0;
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+ else if(nread == CURL_READFUNC_PAUSE) {
+ struct SingleRequest *k = &data->req;
+ /* CURL_READFUNC_PAUSE pauses read callbacks that feed socket writes */
+ k->keepon |= KEEP_SEND_PAUSE; /* mark socket send as paused */
+ if(data->req.upload_chunky) {
+ /* Back out the preallocation done above */
+ data->req.upload_fromhere -= (8 + 2);
+ }
+ *nreadp = 0;
+ return CURLE_OK; /* nothing was read */
+ }
+ else if((size_t)nread > buffersize) {
+ /* the read function returned a too large value */
+ *nreadp = 0;
+ failf(data, "read function returned funny value");
+ return CURLE_READ_ERROR;
+ }
+
+ if(!data->req.forbidchunk && data->req.upload_chunky) {
+ /* if chunked Transfer-Encoding
+ * build chunk:
+ *
+ * <HEX SIZE> CRLF
+ * <DATA> CRLF
+ */
+ /* On non-ASCII platforms the <DATA> may or may not be
+ translated based on set.prefer_ascii while the protocol
+ portion must always be translated to the network encoding.
+ To further complicate matters, line end conversion might be
+ done later on, so we need to prevent CRLFs from becoming
+ CRCRLFs if that's the case. To do this we use bare LFs
+ here, knowing they'll become CRLFs later on.
+ */
+
+ char hexbuffer[11];
+ const char *endofline_native;
+ const char *endofline_network;
+ int hexlen;
+
+ if(
+#ifdef CURL_DO_LINEEND_CONV
+ (data->set.prefer_ascii) ||
+#endif
+ (data->set.crlf)) {
+ /* \n will become \r\n later on */
+ endofline_native = "\n";
+ endofline_network = "\x0a";
+ }
+ else {
+ endofline_native = "\r\n";
+ endofline_network = "\x0d\x0a";
+ }
+ hexlen = snprintf(hexbuffer, sizeof(hexbuffer),
+ "%x%s", nread, endofline_native);
+
+ /* move buffer pointer */
+ data->req.upload_fromhere -= hexlen;
+ nread += hexlen;
+
+ /* copy the prefix to the buffer, leaving out the NUL */
+ memcpy(data->req.upload_fromhere, hexbuffer, hexlen);
+
+ /* always append ASCII CRLF to the data */
+ memcpy(data->req.upload_fromhere + nread,
+ endofline_network,
+ strlen(endofline_network));
+
+#ifdef CURL_DOES_CONVERSIONS
+ CURLcode res;
+ int length;
+ if(data->set.prefer_ascii) {
+ /* translate the protocol and data */
+ length = nread;
+ }
+ else {
+ /* just translate the protocol portion */
+ length = strlen(hexbuffer);
+ }
+ res = Curl_convert_to_network(data, data->req.upload_fromhere, length);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(res)
+ return(res);
+#endif /* CURL_DOES_CONVERSIONS */
+
+ if((nread - hexlen) == 0)
+ /* mark this as done once this chunk is transferred */
+ data->req.upload_done = TRUE;
+
+ nread+=(int)strlen(endofline_native); /* for the added end of line */
+ }
+#ifdef CURL_DOES_CONVERSIONS
+ else if((data->set.prefer_ascii) && (!sending_http_headers)) {
+ CURLcode res;
+ res = Curl_convert_to_network(data, data->req.upload_fromhere, nread);
+ /* Curl_convert_to_network calls failf if unsuccessful */
+ if(res != CURLE_OK)
+ return(res);
+ }
+#endif /* CURL_DOES_CONVERSIONS */
+
+ *nreadp = nread;
+
+ return CURLE_OK;
+}
+
+
+/*
+ * Curl_readrewind() rewinds the read stream. This is typically used for HTTP
+ * POST/PUT with multi-pass authentication when a sending was denied and a
+ * resend is necessary.
+ */
+CURLcode Curl_readrewind(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+
+ conn->bits.rewindaftersend = FALSE; /* we rewind now */
+
+ /* explicitly switch off sending data on this connection now since we are
+ about to restart a new transfer and thus we want to avoid inadvertently
+ sending more data on the existing connection until the next transfer
+ starts */
+ data->req.keepon &= ~KEEP_SEND;
+
+ /* We have sent away data. If not using CURLOPT_POSTFIELDS or
+ CURLOPT_HTTPPOST, call app to rewind
+ */
+ if(data->set.postfields ||
+ (data->set.httpreq == HTTPREQ_POST_FORM))
+ ; /* do nothing */
+ else {
+ if(data->set.seek_func) {
+ int err;
+
+ err = (data->set.seek_func)(data->set.seek_client, 0, SEEK_SET);
+ if(err) {
+ failf(data, "seek callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else if(data->set.ioctl_func) {
+ curlioerr err;
+
+ err = (data->set.ioctl_func)(data, CURLIOCMD_RESTARTREAD,
+ data->set.ioctl_client);
+ infof(data, "the ioctl callback returned %d\n", (int)err);
+
+ if(err) {
+ /* FIXME: convert to a human readable error message */
+ failf(data, "ioctl callback returned error %d", (int)err);
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ else {
+ /* If no CURLOPT_READFUNCTION is used, we know that we operate on a
+ given FILE * stream and we can actually attempt to rewind that
+ ourselves with fseek() */
+ if(data->set.fread_func == (curl_read_callback)fread) {
+ if(-1 != fseek(data->set.in, 0, SEEK_SET))
+ /* successful rewind */
+ return CURLE_OK;
+ }
+
+ /* no callback set or failure above, makes us fail at once */
+ failf(data, "necessary data rewind wasn't possible");
+ return CURLE_SEND_FAIL_REWIND;
+ }
+ }
+ return CURLE_OK;
+}
+
+static int data_pending(const struct connectdata *conn)
+{
+ /* in the case of libssh2, we can never be really sure that we have emptied
+ its internal buffers so we MUST always try until we get EAGAIN back */
+ return conn->handler->protocol&(CURLPROTO_SCP|CURLPROTO_SFTP) ||
+ Curl_ssl_data_pending(conn, FIRSTSOCKET);
+}
+
+static void read_rewind(struct connectdata *conn,
+ size_t thismuch)
+{
+ DEBUGASSERT(conn->read_pos >= thismuch);
+
+ conn->read_pos -= thismuch;
+ conn->bits.stream_was_rewound = TRUE;
+
+#ifdef DEBUGBUILD
+ {
+ char buf[512 + 1];
+ size_t show;
+
+ show = CURLMIN(conn->buf_len - conn->read_pos, sizeof(buf)-1);
+ if(conn->master_buffer) {
+ memcpy(buf, conn->master_buffer + conn->read_pos, show);
+ buf[show] = '\0';
+ }
+ else {
+ buf[0] = '\0';
+ }
+
+ DEBUGF(infof(conn->data,
+ "Buffer after stream rewind (read_pos = %zu): [%s]\n",
+ conn->read_pos, buf));
+ }
+#endif
+}
+
+/*
+ * Check to see if CURLOPT_TIMECONDITION was met by comparing the time of the
+ * remote document with the time provided by CURLOPT_TIMEVAL
+ */
+bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc)
+{
+ if((timeofdoc == 0) || (data->set.timevalue == 0))
+ return TRUE;
+
+ switch(data->set.timecondition) {
+ case CURL_TIMECOND_IFMODSINCE:
+ default:
+ if(timeofdoc <= data->set.timevalue) {
+ infof(data,
+ "The requested document is not new enough\n");
+ data->info.timecond = TRUE;
+ return FALSE;
+ }
+ break;
+ case CURL_TIMECOND_IFUNMODSINCE:
+ if(timeofdoc >= data->set.timevalue) {
+ infof(data,
+ "The requested document is not old enough\n");
+ data->info.timecond = TRUE;
+ return FALSE;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+/*
+ * Go ahead and do a read if we have a readable socket or if
+ * the stream was rewound (in which case we have data in a
+ * buffer)
+ */
+static CURLcode readwrite_data(struct SessionHandle *data,
+ struct connectdata *conn,
+ struct SingleRequest *k,
+ int *didwhat, bool *done)
+{
+ CURLcode result = CURLE_OK;
+ ssize_t nread; /* number of bytes read */
+ size_t excess = 0; /* excess bytes read */
+ bool is_empty_data = FALSE;
+ bool readmore = FALSE; /* used by RTP to signal for more data */
+
+ *done = FALSE;
+
+ /* This is where we loop until we have read everything there is to
+ read or we get a CURLE_AGAIN */
+ do {
+ size_t buffersize = data->set.buffer_size?
+ data->set.buffer_size : BUFSIZE;
+ size_t bytestoread = buffersize;
+
+ if(k->size != -1 && !k->header) {
+ /* make sure we don't read "too much" if we can help it since we
+ might be pipelining and then someone else might want to read what
+ follows! */
+ curl_off_t totalleft = k->size - k->bytecount;
+ if(totalleft < (curl_off_t)bytestoread)
+ bytestoread = (size_t)totalleft;
+ }
+
+ if(bytestoread) {
+ /* receive data from the network! */
+ result = Curl_read(conn, conn->sockfd, k->buf, bytestoread, &nread);
+
+ /* read would've blocked */
+ if(CURLE_AGAIN == result)
+ break; /* get out of loop */
+
+ if(result>0)
+ return result;
+ }
+ else {
+ /* read nothing but since we wanted nothing we consider this an OK
+ situation to proceed from */
+ nread = 0;
+ }
+
+ if((k->bytecount == 0) && (k->writebytecount == 0)) {
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+ if(k->exp100 > EXP100_SEND_DATA)
+ /* set time stamp to compare with when waiting for the 100 */
+ k->start100 = Curl_tvnow();
+ }
+
+ *didwhat |= KEEP_RECV;
+ /* indicates data of zero size, i.e. empty file */
+ is_empty_data = ((nread == 0) && (k->bodywrites == 0)) ? TRUE : FALSE;
+
+ /* NUL terminate, allowing string ops to be used */
+ if(0 < nread || is_empty_data) {
+ k->buf[nread] = 0;
+ }
+ else if(0 >= nread) {
+ /* if we receive 0 or less here, the server closed the connection
+ and we bail out from this! */
+ DEBUGF(infof(data, "nread <= 0, server closed connection, bailing\n"));
+ k->keepon &= ~KEEP_RECV;
+ break;
+ }
+
+ /* Default buffer to use when we write the buffer, it may be changed
+ in the flow below before the actual storing is done. */
+ k->str = k->buf;
+
+ if(conn->handler->readwrite) {
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+ if(readmore)
+ break;
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ /* Since this is a two-state thing, we check if we are parsing
+ headers at the moment or not. */
+ if(k->header) {
+ /* we are in parse-the-header-mode */
+ bool stop_reading = FALSE;
+ result = Curl_http_readwrite_headers(data, conn, &nread, &stop_reading);
+ if(result)
+ return result;
+
+ if(conn->handler->readwrite &&
+ (k->maxdownload <= 0 && nread > 0)) {
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+ if(readmore)
+ break;
+ }
+
+ if(stop_reading) {
+ /* We've stopped dealing with input, get out of the do-while loop */
+
+ if(nread > 0) {
+ if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ infof(data,
+ "Rewinding stream by : %zd"
+ " bytes on url %s (zero-length body)\n",
+ nread, data->state.path);
+ read_rewind(conn, (size_t)nread);
+ }
+ else {
+ infof(data,
+ "Excess found in a non pipelined read:"
+ " excess = %zd"
+ " url = %s (zero-length body)\n",
+ nread, data->state.path);
+ }
+ }
+
+ break;
+ }
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+
+ /* This is not an 'else if' since it may be a rest from the header
+ parsing, where the beginning of the buffer is headers and the end
+ is non-headers. */
+ if(k->str && !k->header && (nread > 0 || is_empty_data)) {
+
+#ifndef CURL_DISABLE_HTTP
+ if(0 == k->bodywrites && !is_empty_data) {
+ /* These checks are only made the first time we are about to
+ write a piece of the body */
+ if(conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_RTSP)) {
+ /* HTTP-only checks */
+
+ if(data->req.newurl) {
+ if(conn->bits.close) {
+ /* Abort after the headers if "follow Location" is set
+ and we're set to close anyway. */
+ k->keepon &= ~KEEP_RECV;
+ *done = TRUE;
+ return CURLE_OK;
+ }
+ /* We have a new url to load, but since we want to be able
+ to re-use this connection properly, we read the full
+ response in "ignore more" */
+ k->ignorebody = TRUE;
+ infof(data, "Ignoring the response-body\n");
+ }
+ if(data->state.resume_from && !k->content_range &&
+ (data->set.httpreq==HTTPREQ_GET) &&
+ !k->ignorebody) {
+ /* we wanted to resume a download, although the server doesn't
+ * seem to support this and we did this with a GET (if it
+ * wasn't a GET we did a POST or PUT resume) */
+ failf(data, "HTTP server doesn't seem to support "
+ "byte ranges. Cannot resume.");
+ return CURLE_RANGE_ERROR;
+ }
+
+ if(data->set.timecondition && !data->state.range) {
+ /* A time condition has been set AND no ranges have been
+ requested. This seems to be what chapter 13.3.4 of
+ RFC 2616 defines to be the correct action for a
+ HTTP/1.1 client */
+
+ if(!Curl_meets_timecondition(data, k->timeofdoc)) {
+ *done = TRUE;
+ /* We're simulating a http 304 from server so we return
+ what should have been returned from the server */
+ data->info.httpcode = 304;
+ infof(data, "Simulate a HTTP 304 response!\n");
+ /* we abort the transfer before it is completed == we ruin the
+ re-use ability. Close the connection */
+ conn->bits.close = TRUE;
+ return CURLE_OK;
+ }
+ } /* we have a time condition */
+
+ } /* this is HTTP or RTSP */
+ } /* this is the first time we write a body part */
+#endif /* CURL_DISABLE_HTTP */
+
+ k->bodywrites++;
+
+ /* pass data to the debug function before it gets "dechunked" */
+ if(data->set.verbose) {
+ if(k->badheader) {
+ Curl_debug(data, CURLINFO_DATA_IN, data->state.headerbuff,
+ (size_t)k->hbuflen, conn);
+ if(k->badheader == HEADER_PARTHEADER)
+ Curl_debug(data, CURLINFO_DATA_IN,
+ k->str, (size_t)nread, conn);
+ }
+ else
+ Curl_debug(data, CURLINFO_DATA_IN,
+ k->str, (size_t)nread, conn);
+ }
+
+#ifndef CURL_DISABLE_HTTP
+ if(k->chunk) {
+ /*
+ * Here comes a chunked transfer flying and we need to decode this
+ * properly. While the name says read, this function both reads
+ * and writes away the data. The returned 'nread' holds the number
+ * of actual data it wrote to the client.
+ */
+
+ CHUNKcode res =
+ Curl_httpchunk_read(conn, k->str, nread, &nread);
+
+ if(CHUNKE_OK < res) {
+ if(CHUNKE_WRITE_ERROR == res) {
+ failf(data, "Failed writing data");
+ return CURLE_WRITE_ERROR;
+ }
+ failf(data, "Problem (%d) in the Chunked-Encoded data", (int)res);
+ return CURLE_RECV_ERROR;
+ }
+ else if(CHUNKE_STOP == res) {
+ size_t dataleft;
+ /* we're done reading chunks! */
+ k->keepon &= ~KEEP_RECV; /* read no more */
+
+ /* There are now possibly N number of bytes at the end of the
+ str buffer that weren't written to the client.
+
+ We DO care about this data if we are pipelining.
+ Push it back to be read on the next pass. */
+
+ dataleft = conn->chunk.dataleft;
+ if(dataleft != 0) {
+ infof(conn->data, "Leftovers after chunking: %zu bytes\n",
+ dataleft);
+ if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ /* only attempt the rewind if we truly are pipelining */
+ infof(conn->data, "Rewinding %zu bytes\n",dataleft);
+ read_rewind(conn, dataleft);
+ }
+ }
+ }
+ /* If it returned OK, we just keep going */
+ }
+#endif /* CURL_DISABLE_HTTP */
+
+ /* Account for body content stored in the header buffer */
+ if(k->badheader && !k->ignorebody) {
+ DEBUGF(infof(data, "Increasing bytecount by %zu from hbuflen\n",
+ k->hbuflen));
+ k->bytecount += k->hbuflen;
+ }
+
+ if((-1 != k->maxdownload) &&
+ (k->bytecount + nread >= k->maxdownload)) {
+
+ excess = (size_t)(k->bytecount + nread - k->maxdownload);
+ if(excess > 0 && !k->ignorebody) {
+ if(Curl_multi_pipeline_enabled(conn->data->multi)) {
+ /* The 'excess' amount below can't be more than BUFSIZE which
+ always will fit in a size_t */
+ infof(data,
+ "Rewinding stream by : %zu"
+ " bytes on url %s (size = %" FORMAT_OFF_T
+ ", maxdownload = %" FORMAT_OFF_T
+ ", bytecount = %" FORMAT_OFF_T ", nread = %zd)\n",
+ excess, data->state.path,
+ k->size, k->maxdownload, k->bytecount, nread);
+ read_rewind(conn, excess);
+ }
+ else {
+ infof(data,
+ "Excess found in a non pipelined read:"
+ " excess = %zu"
+ ", size = %" FORMAT_OFF_T
+ ", maxdownload = %" FORMAT_OFF_T
+ ", bytecount = %" FORMAT_OFF_T "\n",
+ excess, k->size, k->maxdownload, k->bytecount);
+ }
+ }
+
+ nread = (ssize_t) (k->maxdownload - k->bytecount);
+ if(nread < 0 ) /* this should be unusual */
+ nread = 0;
+
+ k->keepon &= ~KEEP_RECV; /* we're done reading */
+ }
+
+ k->bytecount += nread;
+
+ Curl_pgrsSetDownloadCounter(data, k->bytecount);
+
+ if(!k->chunk && (nread || k->badheader || is_empty_data)) {
+ /* If this is chunky transfer, it was already written */
+
+ if(k->badheader && !k->ignorebody) {
+ /* we parsed a piece of data wrongly assuming it was a header
+ and now we output it as body instead */
+
+ /* Don't let excess data pollute body writes */
+ if(k->maxdownload == -1 || (curl_off_t)k->hbuflen <= k->maxdownload)
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ data->state.headerbuff,
+ k->hbuflen);
+ else
+ result = Curl_client_write(conn, CLIENTWRITE_BODY,
+ data->state.headerbuff,
+ (size_t)k->maxdownload);
+
+ if(result)
+ return result;
+ }
+ if(k->badheader < HEADER_ALLBAD) {
+ /* This switch handles various content encodings. If there's an
+ error here, be sure to check over the almost identical code
+ in http_chunks.c.
+ Make sure that ALL_CONTENT_ENCODINGS contains all the
+ encodings handled here. */
+#ifdef HAVE_LIBZ
+ switch (conn->data->set.http_ce_skip ?
+ IDENTITY : k->auto_decoding) {
+ case IDENTITY:
+#endif
+ /* This is the default when the server sends no
+ Content-Encoding header. See Curl_readwrite_init; the
+ memset() call initializes k->auto_decoding to zero. */
+ if(!k->ignorebody) {
+
+#ifndef CURL_DISABLE_POP3
+ if(conn->handler->protocol&CURLPROTO_POP3)
+ result = Curl_pop3_write(conn, k->str, nread);
+ else
+#endif /* CURL_DISABLE_POP3 */
+
+ result = Curl_client_write(conn, CLIENTWRITE_BODY, k->str,
+ nread);
+ }
+#ifdef HAVE_LIBZ
+ break;
+
+ case DEFLATE:
+ /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+ if(!k->ignorebody)
+ result = Curl_unencode_deflate_write(conn, k, nread);
+ break;
+
+ case GZIP:
+ /* Assume CLIENTWRITE_BODY; headers are not encoded. */
+ if(!k->ignorebody)
+ result = Curl_unencode_gzip_write(conn, k, nread);
+ break;
+
+ case COMPRESS:
+ default:
+ failf (data, "Unrecognized content encoding type. "
+ "libcurl understands `identity', `deflate' and `gzip' "
+ "content encodings.");
+ result = CURLE_BAD_CONTENT_ENCODING;
+ break;
+ }
+#endif
+ }
+ k->badheader = HEADER_NORMAL; /* taken care of now */
+
+ if(result)
+ return result;
+ }
+
+ } /* if(! header and data to read ) */
+
+ if(conn->handler->readwrite &&
+ (excess > 0 && !conn->bits.stream_was_rewound)) {
+ /* Parse the excess data */
+ k->str += nread;
+ nread = (ssize_t)excess;
+
+ result = conn->handler->readwrite(data, conn, &nread, &readmore);
+ if(result)
+ return result;
+
+ if(readmore)
+ k->keepon |= KEEP_RECV; /* we're not done reading */
+ break;
+ }
+
+ if(is_empty_data) {
+ /* if we received nothing, the server closed the connection and we
+ are done */
+ k->keepon &= ~KEEP_RECV;
+ }
+
+ } while(data_pending(conn));
+
+ if(((k->keepon & (KEEP_RECV|KEEP_SEND)) == KEEP_SEND) &&
+ conn->bits.close ) {
+ /* When we've read the entire thing and the close bit is set, the server
+ may now close the connection. If there's now any kind of sending going
+ on from our side, we need to stop that immediately. */
+ infof(data, "we are done reading and this is set to close, stop send\n");
+ k->keepon &= ~KEEP_SEND; /* no writing anymore either */
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Send data to upload to the server, when the socket is writable.
+ */
+static CURLcode readwrite_upload(struct SessionHandle *data,
+ struct connectdata *conn,
+ struct SingleRequest *k,
+ int *didwhat)
+{
+ ssize_t i, si;
+ ssize_t bytes_written;
+ CURLcode result;
+ ssize_t nread; /* number of bytes read */
+ bool sending_http_headers = FALSE;
+
+ if((k->bytecount == 0) && (k->writebytecount == 0))
+ Curl_pgrsTime(data, TIMER_STARTTRANSFER);
+
+ *didwhat |= KEEP_SEND;
+
+ /*
+ * We loop here to do the READ and SEND loop until we run out of
+ * data to send or until we get EWOULDBLOCK back
+ *
+ * FIXME: above comment is misleading. Currently no looping is
+ * actually done in do-while loop below.
+ */
+ do {
+
+ /* only read more data if there's no upload data already
+ present in the upload buffer */
+ if(0 == data->req.upload_present) {
+ /* init the "upload from here" pointer */
+ data->req.upload_fromhere = k->uploadbuf;
+
+ if(!k->upload_done) {
+ /* HTTP pollution, this should be written nicer to become more
+ protocol agnostic. */
+ int fillcount;
+ struct HTTP *http = data->req.protop;
+
+ if((k->exp100 == EXP100_SENDING_REQUEST) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* If this call is to send body data, we must take some action:
+ We have sent off the full HTTP 1.1 request, and we shall now
+ go into the Expect: 100 state and await such a header */
+ k->exp100 = EXP100_AWAITING_CONTINUE; /* wait for the header */
+ k->keepon &= ~KEEP_SEND; /* disable writing */
+ k->start100 = Curl_tvnow(); /* timeout count starts now */
+ *didwhat &= ~KEEP_SEND; /* we didn't write anything actually */
+
+ /* set a timeout for the multi interface */
+ Curl_expire(data, CURL_TIMEOUT_EXPECT_100);
+ break;
+ }
+
+ if(conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_RTSP)) {
+ if(http->sending == HTTPSEND_REQUEST)
+ /* We're sending the HTTP request headers, not the data.
+ Remember that so we don't change the line endings. */
+ sending_http_headers = TRUE;
+ else
+ sending_http_headers = FALSE;
+ }
+
+ result = Curl_fillreadbuffer(conn, BUFSIZE, &fillcount);
+ if(result)
+ return result;
+
+ nread = (ssize_t)fillcount;
+ }
+ else
+ nread = 0; /* we're done uploading/reading */
+
+ if(!nread && (k->keepon & KEEP_SEND_PAUSE)) {
+ /* this is a paused transfer */
+ break;
+ }
+ else if(nread<=0) {
+ /* done */
+ k->keepon &= ~KEEP_SEND; /* we're done writing */
+
+ if(conn->bits.rewindaftersend) {
+ result = Curl_readrewind(conn);
+ if(result)
+ return result;
+ }
+ break;
+ }
+
+ /* store number of bytes available for upload */
+ data->req.upload_present = nread;
+
+#ifndef CURL_DISABLE_SMTP
+ if(conn->handler->protocol & CURLPROTO_SMTP) {
+ result = Curl_smtp_escape_eob(conn, nread);
+ if(result)
+ return result;
+ }
+ else
+#endif /* CURL_DISABLE_SMTP */
+
+ /* convert LF to CRLF if so asked */
+ if((!sending_http_headers) && (
+#ifdef CURL_DO_LINEEND_CONV
+ /* always convert if we're FTPing in ASCII mode */
+ (data->set.prefer_ascii) ||
+#endif
+ (data->set.crlf))) {
+ if(data->state.scratch == NULL)
+ data->state.scratch = malloc(2*BUFSIZE);
+ if(data->state.scratch == NULL) {
+ failf (data, "Failed to alloc scratch buffer!");
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /*
+ * ASCII/EBCDIC Note: This is presumably a text (not binary)
+ * transfer so the data should already be in ASCII.
+ * That means the hex values for ASCII CR (0x0d) & LF (0x0a)
+ * must be used instead of the escape sequences \r & \n.
+ */
+ for(i = 0, si = 0; i < nread; i++, si++) {
+ if(data->req.upload_fromhere[i] == 0x0a) {
+ data->state.scratch[si++] = 0x0d;
+ data->state.scratch[si] = 0x0a;
+ if(!data->set.crlf) {
+ /* we're here only because FTP is in ASCII mode...
+ bump infilesize for the LF we just added */
+ data->set.infilesize++;
+ }
+ }
+ else
+ data->state.scratch[si] = data->req.upload_fromhere[i];
+ }
+ if(si != nread) {
+ /* only perform the special operation if we really did replace
+ anything */
+ nread = si;
+
+ /* upload from the new (replaced) buffer instead */
+ data->req.upload_fromhere = data->state.scratch;
+
+ /* set the new amount too */
+ data->req.upload_present = nread;
+ }
+ }
+ } /* if 0 == data->req.upload_present */
+ else {
+ /* We have a partial buffer left from a previous "round". Use
+ that instead of reading more data */
+ }
+
+ /* write to socket (send away data) */
+ result = Curl_write(conn,
+ conn->writesockfd, /* socket to send to */
+ data->req.upload_fromhere, /* buffer pointer */
+ data->req.upload_present, /* buffer size */
+ &bytes_written); /* actually sent */
+
+ if(result)
+ return result;
+
+ if(data->set.verbose)
+ /* show the data before we change the pointer upload_fromhere */
+ Curl_debug(data, CURLINFO_DATA_OUT, data->req.upload_fromhere,
+ (size_t)bytes_written, conn);
+
+ k->writebytecount += bytes_written;
+
+ if(k->writebytecount == data->set.infilesize) {
+ /* we have sent all data we were supposed to */
+ k->upload_done = TRUE;
+ infof(data, "We are completely uploaded and fine\n");
+ }
+
+ if(data->req.upload_present != bytes_written) {
+ /* we only wrote a part of the buffer (if anything), deal with it! */
+
+ /* store the amount of bytes left in the buffer to write */
+ data->req.upload_present -= bytes_written;
+
+ /* advance the pointer where to find the buffer when the next send
+ is to happen */
+ data->req.upload_fromhere += bytes_written;
+ }
+ else {
+ /* we've uploaded that buffer now */
+ data->req.upload_fromhere = k->uploadbuf;
+ data->req.upload_present = 0; /* no more bytes left */
+
+ if(k->upload_done) {
+ /* switch off writing, we're done! */
+ k->keepon &= ~KEEP_SEND; /* we're done writing */
+ }
+ }
+
+ Curl_pgrsSetUploadCounter(data, k->writebytecount);
+
+ } WHILE_FALSE; /* just to break out from! */
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_readwrite() is the low-level function to be called when data is to
+ * be read and written to/from the connection.
+ */
+CURLcode Curl_readwrite(struct connectdata *conn,
+ bool *done)
+{
+ struct SessionHandle *data = conn->data;
+ struct SingleRequest *k = &data->req;
+ CURLcode result;
+ int didwhat=0;
+
+ curl_socket_t fd_read;
+ curl_socket_t fd_write;
+ int select_res = conn->cselect_bits;
+
+ conn->cselect_bits = 0;
+
+ /* only use the proper socket if the *_HOLD bit is not set simultaneously as
+ then we are in rate limiting state in that transfer direction */
+
+ if((k->keepon & KEEP_RECVBITS) == KEEP_RECV)
+ fd_read = conn->sockfd;
+ else
+ fd_read = CURL_SOCKET_BAD;
+
+ if((k->keepon & KEEP_SENDBITS) == KEEP_SEND)
+ fd_write = conn->writesockfd;
+ else
+ fd_write = CURL_SOCKET_BAD;
+
+ if(!select_res) /* Call for select()/poll() only, if read/write/error
+ status is not known. */
+ select_res = Curl_socket_ready(fd_read, fd_write, 0);
+
+ if(select_res == CURL_CSELECT_ERR) {
+ failf(data, "select/poll returned error");
+ return CURLE_SEND_ERROR;
+ }
+
+ /* We go ahead and do a read if we have a readable socket or if
+ the stream was rewound (in which case we have data in a
+ buffer) */
+ if((k->keepon & KEEP_RECV) &&
+ ((select_res & CURL_CSELECT_IN) || conn->bits.stream_was_rewound)) {
+
+ result = readwrite_data(data, conn, k, &didwhat, done);
+ if(result || *done)
+ return result;
+ }
+
+ /* If we still have writing to do, we check if we have a writable socket. */
+ if((k->keepon & KEEP_SEND) && (select_res & CURL_CSELECT_OUT)) {
+ /* write */
+
+ result = readwrite_upload(data, conn, k, &didwhat);
+ if(result)
+ return result;
+ }
+
+ k->now = Curl_tvnow();
+ if(didwhat) {
+ /* Update read/write counters */
+ if(k->bytecountp)
+ *k->bytecountp = k->bytecount; /* read count */
+ if(k->writebytecountp)
+ *k->writebytecountp = k->writebytecount; /* write count */
+ }
+ else {
+ /* no read no write, this is a timeout? */
+ if(k->exp100 == EXP100_AWAITING_CONTINUE) {
+ /* This should allow some time for the header to arrive, but only a
+ very short time as otherwise it'll be too much wasted time too
+ often. */
+
+ /* Quoting RFC2616, section "8.2.3 Use of the 100 (Continue) Status":
+
+ Therefore, when a client sends this header field to an origin server
+ (possibly via a proxy) from which it has never seen a 100 (Continue)
+ status, the client SHOULD NOT wait for an indefinite period before
+ sending the request body.
+
+ */
+
+ long ms = Curl_tvdiff(k->now, k->start100);
+ if(ms > CURL_TIMEOUT_EXPECT_100) {
+ /* we've waited long enough, continue anyway */
+ k->exp100 = EXP100_SEND_DATA;
+ k->keepon |= KEEP_SEND;
+ infof(data, "Done waiting for 100-continue\n");
+ }
+ }
+ }
+
+ if(Curl_pgrsUpdate(conn))
+ result = CURLE_ABORTED_BY_CALLBACK;
+ else
+ result = Curl_speedcheck(data, k->now);
+ if(result)
+ return result;
+
+ if(k->keepon) {
+ if(0 > Curl_timeleft(data, &k->now, FALSE)) {
+ if(k->size != -1) {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ FORMAT_OFF_T " out of %" FORMAT_OFF_T " bytes received",
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount,
+ k->size);
+ }
+ else {
+ failf(data, "Operation timed out after %ld milliseconds with %"
+ FORMAT_OFF_T " bytes received",
+ Curl_tvdiff(k->now, data->progress.t_startsingle), k->bytecount);
+ }
+ return CURLE_OPERATION_TIMEDOUT;
+ }
+ }
+ else {
+ /*
+ * The transfer has been performed. Just make some general checks before
+ * returning.
+ */
+
+ if(!(data->set.opt_no_body) && (k->size != -1) &&
+ (k->bytecount != k->size) &&
+#ifdef CURL_DO_LINEEND_CONV
+ /* Most FTP servers don't adjust their file SIZE response for CRLFs,
+ so we'll check to see if the discrepancy can be explained
+ by the number of CRLFs we've changed to LFs.
+ */
+ (k->bytecount != (k->size + data->state.crlf_conversions)) &&
+#endif /* CURL_DO_LINEEND_CONV */
+ !data->req.newurl) {
+ failf(data, "transfer closed with %" FORMAT_OFF_T
+ " bytes remaining to read",
+ k->size - k->bytecount);
+ return CURLE_PARTIAL_FILE;
+ }
+ else if(!(data->set.opt_no_body) &&
+ k->chunk &&
+ (conn->chunk.state != CHUNK_STOP)) {
+ /*
+ * In chunked mode, return an error if the connection is closed prior to
+ * the empty (terminating) chunk is read.
+ *
+ * The condition above used to check for
+ * conn->proto.http->chunk.datasize != 0 which is true after reading
+ * *any* chunk, not just the empty chunk.
+ *
+ */
+ failf(data, "transfer closed with outstanding read data remaining");
+ return CURLE_PARTIAL_FILE;
+ }
+ if(Curl_pgrsUpdate(conn))
+ return CURLE_ABORTED_BY_CALLBACK;
+ }
+
+ /* Now update the "done" boolean we return */
+ *done = (0 == (k->keepon&(KEEP_RECV|KEEP_SEND|
+ KEEP_RECV_PAUSE|KEEP_SEND_PAUSE))) ? TRUE : FALSE;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_single_getsock() gets called by the multi interface code when the app
+ * has requested to get the sockets for the current connection. This function
+ * will then be called once for every connection that the multi interface
+ * keeps track of. This function will only be called for connections that are
+ * in the proper state to have this information available.
+ */
+int Curl_single_getsock(const struct connectdata *conn,
+ curl_socket_t *sock, /* points to numsocks number
+ of sockets */
+ int numsocks)
+{
+ const struct SessionHandle *data = conn->data;
+ int bitmap = GETSOCK_BLANK;
+ unsigned sockindex = 0;
+
+ if(conn->handler->perform_getsock)
+ return conn->handler->perform_getsock(conn, sock, numsocks);
+
+ if(numsocks < 2)
+ /* simple check but we might need two slots */
+ return GETSOCK_BLANK;
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_RECVBITS) == KEEP_RECV) {
+
+ DEBUGASSERT(conn->sockfd != CURL_SOCKET_BAD);
+
+ bitmap |= GETSOCK_READSOCK(sockindex);
+ sock[sockindex] = conn->sockfd;
+ }
+
+ /* don't include HOLD and PAUSE connections */
+ if((data->req.keepon & KEEP_SENDBITS) == KEEP_SEND) {
+
+ if((conn->sockfd != conn->writesockfd) ||
+ !(data->req.keepon & KEEP_RECV)) {
+ /* only if they are not the same socket or we didn't have a readable
+ one, we increase index */
+ if(data->req.keepon & KEEP_RECV)
+ sockindex++; /* increase index if we need two entries */
+
+ DEBUGASSERT(conn->writesockfd != CURL_SOCKET_BAD);
+
+ sock[sockindex] = conn->writesockfd;
+ }
+
+ bitmap |= GETSOCK_WRITESOCK(sockindex);
+ }
+
+ return bitmap;
+}
+
+/*
+ * Determine optimum sleep time based on configured rate, current rate,
+ * and packet size.
+ * Returns value in milliseconds.
+ *
+ * The basic idea is to adjust the desired rate up/down in this method
+ * based on whether we are running too slow or too fast. Then, calculate
+ * how many milliseconds to wait for the next packet to achieve this new
+ * rate.
+ */
+long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
+ int pkt_size)
+{
+ curl_off_t min_sleep = 0;
+ curl_off_t rv = 0;
+
+ if(rate_bps == 0)
+ return 0;
+
+ /* If running faster than about .1% of the desired speed, slow
+ * us down a bit. Use shift instead of division as the 0.1%
+ * cutoff is arbitrary anyway.
+ */
+ if(cur_rate_bps > (rate_bps + (rate_bps >> 10))) {
+ /* running too fast, decrease target rate by 1/64th of rate */
+ rate_bps -= rate_bps >> 6;
+ min_sleep = 1;
+ }
+ else if(cur_rate_bps < (rate_bps - (rate_bps >> 10))) {
+ /* running too slow, increase target rate by 1/64th of rate */
+ rate_bps += rate_bps >> 6;
+ }
+
+ /* Determine number of milliseconds to wait until we do
+ * the next packet at the adjusted rate. We should wait
+ * longer when using larger packets, for instance.
+ */
+ rv = ((curl_off_t)((pkt_size * 8) * 1000) / rate_bps);
+
+ /* Catch rounding errors and always slow down at least 1ms if
+ * we are running too fast.
+ */
+ if(rv < min_sleep)
+ rv = min_sleep;
+
+ /* Bound value to fit in 'long' on 32-bit platform. That's
+ * plenty long enough anyway!
+ */
+ if(rv > 0x7fffffff)
+ rv = 0x7fffffff;
+
+ return (long)rv;
+}
+
+/*
+ * Curl_pretransfer() is called immediately before a transfer starts.
+ */
+CURLcode Curl_pretransfer(struct SessionHandle *data)
+{
+ CURLcode res;
+ if(!data->change.url) {
+ /* we can't do anything without URL */
+ failf(data, "No URL set!");
+ return CURLE_URL_MALFORMAT;
+ }
+
+ /* Init the SSL session ID cache here. We do it here since we want to do it
+ after the *_setopt() calls (that could specify the size of the cache) but
+ before any transfer takes place. */
+ res = Curl_ssl_initsessions(data, data->set.ssl.max_ssl_sessions);
+ if(res)
+ return res;
+
+ data->set.followlocation=0; /* reset the location-follow counter */
+ data->state.this_is_a_follow = FALSE; /* reset this */
+ data->state.errorbuf = FALSE; /* no error has occurred */
+ data->state.httpversion = 0; /* don't assume any particular server version */
+
+ data->state.ssl_connect_retry = FALSE;
+
+ data->state.authproblem = FALSE;
+ data->state.authhost.want = data->set.httpauth;
+ data->state.authproxy.want = data->set.proxyauth;
+ Curl_safefree(data->info.wouldredirect);
+ data->info.wouldredirect = NULL;
+
+ /* If there is a list of cookie files to read, do it now! */
+ if(data->change.cookielist)
+ Curl_cookie_loadfiles(data);
+
+ /* If there is a list of host pairs to deal with */
+ if(data->change.resolve)
+ res = Curl_loadhostpairs(data);
+
+ if(!res) {
+ /* Allow data->set.use_port to set which port to use. This needs to be
+ * disabled for example when we follow Location: headers to URLs using
+ * different ports! */
+ data->state.allow_port = TRUE;
+
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+ /*************************************************************
+ * Tell signal handler to ignore SIGPIPE
+ *************************************************************/
+ if(!data->set.no_signal)
+ data->state.prev_signal = signal(SIGPIPE, SIG_IGN);
+#endif
+
+ Curl_initinfo(data); /* reset session-specific information "variables" */
+ Curl_pgrsStartNow(data);
+
+ if(data->set.timeout)
+ Curl_expire(data, data->set.timeout);
+
+ if(data->set.connecttimeout)
+ Curl_expire(data, data->set.connecttimeout);
+
+ /* In case the handle is re-used and an authentication method was picked
+ in the session we need to make sure we only use the one(s) we now
+ consider to be fine */
+ data->state.authhost.picked &= data->state.authhost.want;
+ data->state.authproxy.picked &= data->state.authproxy.want;
+ }
+
+ return res;
+}
+
+/*
+ * Curl_posttransfer() is called immediately after a transfer ends
+ */
+CURLcode Curl_posttransfer(struct SessionHandle *data)
+{
+#if defined(HAVE_SIGNAL) && defined(SIGPIPE) && !defined(HAVE_MSG_NOSIGNAL)
+ /* restore the signal handler for SIGPIPE before we get back */
+ if(!data->set.no_signal)
+ signal(SIGPIPE, data->state.prev_signal);
+#else
+ (void)data; /* unused parameter */
+#endif
+
+ return CURLE_OK;
+}
+
+#ifndef CURL_DISABLE_HTTP
+/*
+ * strlen_url() returns the length of the given URL if the spaces within the
+ * URL were properly URL encoded.
+ */
+static size_t strlen_url(const char *url)
+{
+ const char *ptr;
+ size_t newlen=0;
+ bool left=TRUE; /* left side of the ? */
+
+ for(ptr=url; *ptr; ptr++) {
+ switch(*ptr) {
+ case '?':
+ left=FALSE;
+ /* fall through */
+ default:
+ newlen++;
+ break;
+ case ' ':
+ if(left)
+ newlen+=3;
+ else
+ newlen++;
+ break;
+ }
+ }
+ return newlen;
+}
+
+/* strcpy_url() copies a url to a output buffer and URL-encodes the spaces in
+ * the source URL accordingly.
+ */
+static void strcpy_url(char *output, const char *url)
+{
+ /* we must add this with whitespace-replacing */
+ bool left=TRUE;
+ const char *iptr;
+ char *optr = output;
+ for(iptr = url; /* read from here */
+ *iptr; /* until zero byte */
+ iptr++) {
+ switch(*iptr) {
+ case '?':
+ left=FALSE;
+ /* fall through */
+ default:
+ *optr++=*iptr;
+ break;
+ case ' ':
+ if(left) {
+ *optr++='%'; /* add a '%' */
+ *optr++='2'; /* add a '2' */
+ *optr++='0'; /* add a '0' */
+ }
+ else
+ *optr++='+'; /* add a '+' here */
+ break;
+ }
+ }
+ *optr=0; /* zero terminate output buffer */
+
+}
+
+/*
+ * Returns true if the given URL is absolute (as opposed to relative)
+ */
+static bool is_absolute_url(const char *url)
+{
+ char prot[16]; /* URL protocol string storage */
+ char letter; /* used for a silly sscanf */
+
+ return (2 == sscanf(url, "%15[^?&/:]://%c", prot, &letter)) ? TRUE : FALSE;
+}
+
+/*
+ * Concatenate a relative URL to a base URL making it absolute.
+ * URL-encodes any spaces.
+ * The returned pointer must be freed by the caller unless NULL
+ * (returns NULL on out of memory).
+ */
+static char *concat_url(const char *base, const char *relurl)
+{
+ /***
+ TRY to append this new path to the old URL
+ to the right of the host part. Oh crap, this is doomed to cause
+ problems in the future...
+ */
+ char *newest;
+ char *protsep;
+ char *pathsep;
+ size_t newlen;
+
+ const char *useurl = relurl;
+ size_t urllen;
+
+ /* we must make our own copy of the URL to play with, as it may
+ point to read-only data */
+ char *url_clone=strdup(base);
+
+ if(!url_clone)
+ return NULL; /* skip out of this NOW */
+
+ /* protsep points to the start of the host name */
+ protsep=strstr(url_clone, "//");
+ if(!protsep)
+ protsep=url_clone;
+ else
+ protsep+=2; /* pass the slashes */
+
+ if('/' != relurl[0]) {
+ int level=0;
+
+ /* First we need to find out if there's a ?-letter in the URL,
+ and cut it and the right-side of that off */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep=0;
+
+ /* we have a relative path to append to the last slash if there's one
+ available, or if the new URL is just a query string (starts with a
+ '?') we append the new one at the end of the entire currently worked
+ out URL */
+ if(useurl[0] != '?') {
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep=0;
+ }
+
+ /* Check if there's any slash after the host name, and if so, remember
+ that position instead */
+ pathsep = strchr(protsep, '/');
+ if(pathsep)
+ protsep = pathsep+1;
+ else
+ protsep = NULL;
+
+ /* now deal with one "./" or any amount of "../" in the newurl
+ and act accordingly */
+
+ if((useurl[0] == '.') && (useurl[1] == '/'))
+ useurl+=2; /* just skip the "./" */
+
+ while((useurl[0] == '.') &&
+ (useurl[1] == '.') &&
+ (useurl[2] == '/')) {
+ level++;
+ useurl+=3; /* pass the "../" */
+ }
+
+ if(protsep) {
+ while(level--) {
+ /* cut off one more level from the right of the original URL */
+ pathsep = strrchr(protsep, '/');
+ if(pathsep)
+ *pathsep=0;
+ else {
+ *protsep=0;
+ break;
+ }
+ }
+ }
+ }
+ else {
+ /* We got a new absolute path for this server */
+
+ if((relurl[0] == '/') && (relurl[1] == '/')) {
+ /* the new URL starts with //, just keep the protocol part from the
+ original one */
+ *protsep=0;
+ useurl = &relurl[2]; /* we keep the slashes from the original, so we
+ skip the new ones */
+ }
+ else {
+ /* cut off the original URL from the first slash, or deal with URLs
+ without slash */
+ pathsep = strchr(protsep, '/');
+ if(pathsep) {
+ /* When people use badly formatted URLs, such as
+ "http://www.url.com?dir=/home/daniel" we must not use the first
+ slash, if there's a ?-letter before it! */
+ char *sep = strchr(protsep, '?');
+ if(sep && (sep < pathsep))
+ pathsep = sep;
+ *pathsep=0;
+ }
+ else {
+ /* There was no slash. Now, since we might be operating on a badly
+ formatted URL, such as "http://www.url.com?id=2380" which doesn't
+ use a slash separator as it is supposed to, we need to check for a
+ ?-letter as well! */
+ pathsep = strchr(protsep, '?');
+ if(pathsep)
+ *pathsep=0;
+ }
+ }
+ }
+
+ /* If the new part contains a space, this is a mighty stupid redirect
+ but we still make an effort to do "right". To the left of a '?'
+ letter we replace each space with %20 while it is replaced with '+'
+ on the right side of the '?' letter.
+ */
+ newlen = strlen_url(useurl);
+
+ urllen = strlen(url_clone);
+
+ newest = malloc(urllen + 1 + /* possible slash */
+ newlen + 1 /* zero byte */);
+
+ if(!newest) {
+ free(url_clone); /* don't leak this */
+ return NULL;
+ }
+
+ /* copy over the root url part */
+ memcpy(newest, url_clone, urllen);
+
+ /* check if we need to append a slash */
+ if(('/' == useurl[0]) || (protsep && !*protsep) || ('?' == useurl[0]))
+ ;
+ else
+ newest[urllen++]='/';
+
+ /* then append the new piece on the right side */
+ strcpy_url(&newest[urllen], useurl);
+
+ free(url_clone);
+
+ return newest;
+}
+#endif /* CURL_DISABLE_HTTP */
+
+/*
+ * Curl_follow() handles the URL redirect magic. Pass in the 'newurl' string
+ * as given by the remote server and set up the new URL to request.
+ */
+CURLcode Curl_follow(struct SessionHandle *data,
+ char *newurl, /* this 'newurl' is the Location: string,
+ and it must be malloc()ed before passed
+ here */
+ followtype type) /* see transfer.h */
+{
+#ifdef CURL_DISABLE_HTTP
+ (void)data;
+ (void)newurl;
+ (void)type;
+ /* Location: following will not happen when HTTP is disabled */
+ return CURLE_TOO_MANY_REDIRECTS;
+#else
+
+ /* Location: redirect */
+ bool disallowport = FALSE;
+
+ if(type == FOLLOW_REDIR) {
+ if((data->set.maxredirs != -1) &&
+ (data->set.followlocation >= data->set.maxredirs)) {
+ failf(data,"Maximum (%ld) redirects followed", data->set.maxredirs);
+ return CURLE_TOO_MANY_REDIRECTS;
+ }
+
+ /* mark the next request as a followed location: */
+ data->state.this_is_a_follow = TRUE;
+
+ data->set.followlocation++; /* count location-followers */
+
+ if(data->set.http_auto_referer) {
+ /* We are asked to automatically set the previous URL as the referer
+ when we get the next URL. We pick the ->url field, which may or may
+ not be 100% correct */
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+
+ data->change.referer = strdup(data->change.url);
+ if(!data->change.referer)
+ return CURLE_OUT_OF_MEMORY;
+ data->change.referer_alloc = TRUE; /* yes, free this later */
+ }
+ }
+
+ if(!is_absolute_url(newurl)) {
+ /***
+ *DANG* this is an RFC 2068 violation. The URL is supposed
+ to be absolute and this doesn't seem to be that!
+ */
+ char *absolute = concat_url(data->change.url, newurl);
+ if(!absolute)
+ return CURLE_OUT_OF_MEMORY;
+ free(newurl);
+ newurl = absolute;
+ }
+ else {
+ /* This is an absolute URL, don't allow the custom port number */
+ disallowport = TRUE;
+
+ if(strchr(newurl, ' ')) {
+ /* This new URL contains at least one space, this is a mighty stupid
+ redirect but we still make an effort to do "right". */
+ char *newest;
+ size_t newlen = strlen_url(newurl);
+
+ newest = malloc(newlen+1); /* get memory for this */
+ if(!newest)
+ return CURLE_OUT_OF_MEMORY;
+ strcpy_url(newest, newurl); /* create a space-free URL */
+
+ free(newurl); /* that was no good */
+ newurl = newest; /* use this instead now */
+ }
+
+ }
+
+ if(type == FOLLOW_FAKE) {
+ /* we're only figuring out the new url if we would've followed locations
+ but now we're done so we can get out! */
+ data->info.wouldredirect = newurl;
+ return CURLE_OK;
+ }
+
+ if(disallowport)
+ data->state.allow_port = FALSE;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = newurl;
+ data->change.url_alloc = TRUE;
+ newurl = NULL; /* don't free! */
+
+ infof(data, "Issue another request to this URL: '%s'\n", data->change.url);
+
+ /*
+ * We get here when the HTTP code is 300-399 (and 401). We need to perform
+ * differently based on exactly what return code there was.
+ *
+ * News from 7.10.6: we can also get here on a 401 or 407, in case we act on
+ * a HTTP (proxy-) authentication scheme other than Basic.
+ */
+ switch(data->info.httpcode) {
+ /* 401 - Act on a WWW-Authenticate, we keep on moving and do the
+ Authorization: XXXX header in the HTTP request code snippet */
+ /* 407 - Act on a Proxy-Authenticate, we keep on moving and do the
+ Proxy-Authorization: XXXX header in the HTTP request code snippet */
+ /* 300 - Multiple Choices */
+ /* 306 - Not used */
+ /* 307 - Temporary Redirect */
+ default: /* for all above (and the unknown ones) */
+ /* Some codes are explicitly mentioned since I've checked RFC2616 and they
+ * seem to be OK to POST to.
+ */
+ break;
+ case 301: /* Moved Permanently */
+ /* (quote from RFC2616, section 10.3.2):
+ *
+ * When automatically redirecting a POST request after receiving a 301
+ * status code, some existing HTTP/1.0 user agents will erroneously change
+ * it into a GET request.
+ *
+ * ----
+ *
+ * As most of the important user agents do this obvious RFC2616 violation,
+ * many webservers expect this. So these servers often answers to a POST
+ * request with an error page. To be sure that libcurl gets the page that
+ * most user agents would get, libcurl has to force GET.
+ *
+ * This behavior can be overridden with CURLOPT_POSTREDIR.
+ */
+ if((data->set.httpreq == HTTPREQ_POST
+ || data->set.httpreq == HTTPREQ_POST_FORM)
+ && !(data->set.keep_post & CURL_REDIR_POST_301)) {
+ infof(data,
+ "Violate RFC 2616/10.3.2 and switch from POST to GET\n");
+ data->set.httpreq = HTTPREQ_GET;
+ }
+ break;
+ case 302: /* Found */
+ /* (From 10.3.3)
+
+ Note: RFC 1945 and RFC 2068 specify that the client is not allowed
+ to change the method on the redirected request. However, most
+ existing user agent implementations treat 302 as if it were a 303
+ response, performing a GET on the Location field-value regardless
+ of the original request method. The status codes 303 and 307 have
+ been added for servers that wish to make unambiguously clear which
+ kind of reaction is expected of the client.
+
+ (From 10.3.4)
+
+ Note: Many pre-HTTP/1.1 user agents do not understand the 303
+ status. When interoperability with such clients is a concern, the
+ 302 status code may be used instead, since most user agents react
+ to a 302 response as described here for 303.
+
+ This behavior can be overridden with CURLOPT_POSTREDIR
+ */
+ if((data->set.httpreq == HTTPREQ_POST
+ || data->set.httpreq == HTTPREQ_POST_FORM)
+ && !(data->set.keep_post & CURL_REDIR_POST_302)) {
+ infof(data,
+ "Violate RFC 2616/10.3.3 and switch from POST to GET\n");
+ data->set.httpreq = HTTPREQ_GET;
+ }
+ break;
+
+ case 303: /* See Other */
+ /* Disable both types of POSTs, unless the user explicitely
+ asks for POST after POST */
+ if(data->set.httpreq != HTTPREQ_GET
+ && !(data->set.keep_post & CURL_REDIR_POST_303)) {
+ data->set.httpreq = HTTPREQ_GET; /* enforce GET request */
+ infof(data, "Disables POST, goes with %s\n",
+ data->set.opt_no_body?"HEAD":"GET");
+ }
+ break;
+ case 304: /* Not Modified */
+ /* 304 means we did a conditional request and it was "Not modified".
+ * We shouldn't get any Location: header in this response!
+ */
+ break;
+ case 305: /* Use Proxy */
+ /* (quote from RFC2616, section 10.3.6):
+ * "The requested resource MUST be accessed through the proxy given
+ * by the Location field. The Location field gives the URI of the
+ * proxy. The recipient is expected to repeat this single request
+ * via the proxy. 305 responses MUST only be generated by origin
+ * servers."
+ */
+ break;
+ }
+ Curl_pgrsTime(data, TIMER_REDIRECT);
+ Curl_pgrsResetTimesSizes(data);
+
+ return CURLE_OK;
+#endif /* CURL_DISABLE_HTTP */
+}
+
+CURLcode
+Curl_reconnect_request(struct connectdata **connp)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn = *connp;
+ struct SessionHandle *data = conn->data;
+
+ /* This was a re-use of a connection and we got a write error in the
+ * DO-phase. Then we DISCONNECT this connection and have another attempt to
+ * CONNECT and then DO again! The retry cannot possibly find another
+ * connection to re-use, since we only keep one possible connection for
+ * each. */
+
+ infof(data, "Re-used connection seems dead, get a new one\n");
+
+ conn->bits.close = TRUE; /* enforce close of this connection */
+ result = Curl_done(&conn, result, FALSE); /* we are so done with this */
+
+ /* conn may no longer be a good pointer, clear it to avoid mistakes by
+ parent functions */
+ *connp = NULL;
+
+ /*
+ * According to bug report #1330310. We need to check for CURLE_SEND_ERROR
+ * here as well. I figure this could happen when the request failed on a FTP
+ * connection and thus Curl_done() itself tried to use the connection
+ * (again). Slight Lack of feedback in the report, but I don't think this
+ * extra check can do much harm.
+ */
+ if((CURLE_OK == result) || (CURLE_SEND_ERROR == result)) {
+ bool async;
+ bool protocol_done = TRUE;
+
+ /* Now, redo the connect and get a new connection */
+ result = Curl_connect(data, connp, &async, &protocol_done);
+ if(CURLE_OK == result) {
+ /* We have connected or sent away a name resolve query fine */
+
+ conn = *connp; /* setup conn to again point to something nice */
+ if(async) {
+ /* Now, if async is TRUE here, we need to wait for the name
+ to resolve */
+ result = Curl_resolver_wait_resolv(conn, NULL);
+ if(result)
+ return result;
+
+ /* Resolved, continue with the connection */
+ result = Curl_async_resolved(conn, &protocol_done);
+ if(result)
+ return result;
+ }
+ }
+ }
+
+ return result;
+}
+
+/* Returns CURLE_OK *and* sets '*url' if a request retry is wanted.
+
+ NOTE: that the *url is malloc()ed. */
+CURLcode Curl_retry_request(struct connectdata *conn,
+ char **url)
+{
+ struct SessionHandle *data = conn->data;
+
+ *url = NULL;
+
+ /* if we're talking upload, we can't do the checks below, unless the protocol
+ is HTTP as when uploading over HTTP we will still get a response */
+ if(data->set.upload &&
+ !(conn->handler->protocol&(CURLPROTO_HTTP|CURLPROTO_RTSP)))
+ return CURLE_OK;
+
+ if(/* workaround for broken TLS servers */ data->state.ssl_connect_retry ||
+ ((data->req.bytecount +
+ data->req.headerbytecount == 0) &&
+ conn->bits.reuse &&
+ !data->set.opt_no_body &&
+ data->set.rtspreq != RTSPREQ_RECEIVE)) {
+ /* We got no data, we attempted to re-use a connection and yet we want a
+ "body". This might happen if the connection was left alive when we were
+ done using it before, but that was closed when we wanted to read from
+ it again. Bad luck. Retry the same request on a fresh connect! */
+ infof(conn->data, "Connection died, retrying a fresh connect\n");
+ *url = strdup(conn->data->change.url);
+ if(!*url)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->bits.close = TRUE; /* close this connection */
+ conn->bits.retry = TRUE; /* mark this as a connection we're about
+ to retry. Marking it this way should
+ prevent i.e HTTP transfers to return
+ error just because nothing has been
+ transferred! */
+
+
+ if(conn->handler->protocol&CURLPROTO_HTTP) {
+ struct HTTP *http = data->req.protop;
+ if(http->writebytecount)
+ return Curl_readrewind(conn);
+ }
+ }
+ return CURLE_OK;
+}
+
+/*
+ * Curl_setup_transfer() is called to setup some basic properties for the
+ * upcoming transfer.
+ */
+void
+Curl_setup_transfer(
+ struct connectdata *conn, /* connection data */
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ curl_off_t *bytecountp, /* return number of bytes read or NULL */
+ int writesockindex, /* socket index to write to, it may very well be
+ the same we read from. -1 disables */
+ curl_off_t *writecountp /* return number of bytes written or NULL */
+ )
+{
+ struct SessionHandle *data;
+ struct SingleRequest *k;
+
+ DEBUGASSERT(conn != NULL);
+
+ data = conn->data;
+ k = &data->req;
+
+ DEBUGASSERT((sockindex <= 1) && (sockindex >= -1));
+
+ /* now copy all input parameters */
+ conn->sockfd = sockindex == -1 ?
+ CURL_SOCKET_BAD : conn->sock[sockindex];
+ conn->writesockfd = writesockindex == -1 ?
+ CURL_SOCKET_BAD:conn->sock[writesockindex];
+ k->getheader = getheader;
+
+ k->size = size;
+ k->bytecountp = bytecountp;
+ k->writebytecountp = writecountp;
+
+ /* The code sequence below is placed in this function just because all
+ necessary input is not always known in do_complete() as this function may
+ be called after that */
+
+ if(!k->getheader) {
+ k->header = FALSE;
+ if(size > 0)
+ Curl_pgrsSetDownloadSize(data, size);
+ }
+ /* we want header and/or body, if neither then don't do this! */
+ if(k->getheader || !data->set.opt_no_body) {
+
+ if(conn->sockfd != CURL_SOCKET_BAD)
+ k->keepon |= KEEP_RECV;
+
+ if(conn->writesockfd != CURL_SOCKET_BAD) {
+ struct HTTP *http = data->req.protop;
+ /* HTTP 1.1 magic:
+
+ Even if we require a 100-return code before uploading data, we might
+ need to write data before that since the REQUEST may not have been
+ finished sent off just yet.
+
+ Thus, we must check if the request has been sent before we set the
+ state info where we wait for the 100-return code
+ */
+ if((data->state.expect100header) &&
+ (conn->handler->protocol&CURLPROTO_HTTP) &&
+ (http->sending == HTTPSEND_BODY)) {
+ /* wait with write until we either got 100-continue or a timeout */
+ k->exp100 = EXP100_AWAITING_CONTINUE;
+ k->start100 = Curl_tvnow();
+
+ /* Set a timeout for the multi interface. Add the inaccuracy margin so
+ that we don't fire slightly too early and get denied to run. */
+ Curl_expire(data, CURL_TIMEOUT_EXPECT_100 +
+ MULTI_TIMEOUT_INACCURACY / 1000);
+ }
+ else {
+ if(data->state.expect100header)
+ /* when we've sent off the rest of the headers, we must await a
+ 100-continue but first finish sending the request */
+ k->exp100 = EXP100_SENDING_REQUEST;
+
+ /* enable the write bit when we're not waiting for continue */
+ k->keepon |= KEEP_SEND;
+ }
+ } /* if(conn->writesockfd != CURL_SOCKET_BAD) */
+ } /* if(k->getheader || !data->set.opt_no_body) */
+
+}
diff --git a/libs/libcurl/src/transfer.h b/libs/libcurl/src/transfer.h
new file mode 100644
index 0000000000..ad4a3acd67
--- /dev/null
+++ b/libs/libcurl/src/transfer.h
@@ -0,0 +1,70 @@
+#ifndef HEADER_CURL_TRANSFER_H
+#define HEADER_CURL_TRANSFER_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.
+ *
+ ***************************************************************************/
+
+CURLcode Curl_pretransfer(struct SessionHandle *data);
+CURLcode Curl_second_connect(struct connectdata *conn);
+CURLcode Curl_posttransfer(struct SessionHandle *data);
+
+typedef enum {
+ FOLLOW_NONE, /* not used within the function, just a placeholder to
+ allow initing to this */
+ FOLLOW_FAKE, /* only records stuff, not actually following */
+ FOLLOW_RETRY, /* set if this is a request retry as opposed to a real
+ redirect following */
+ FOLLOW_REDIR, /* a full true redirect */
+ FOLLOW_LAST /* never used */
+} followtype;
+
+CURLcode Curl_follow(struct SessionHandle *data, char *newurl,
+ followtype type);
+
+
+CURLcode Curl_readwrite(struct connectdata *conn, bool *done);
+int Curl_single_getsock(const struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+CURLcode Curl_readrewind(struct connectdata *conn);
+CURLcode Curl_fillreadbuffer(struct connectdata *conn, int bytes, int *nreadp);
+CURLcode Curl_reconnect_request(struct connectdata **connp);
+CURLcode Curl_retry_request(struct connectdata *conn, char **url);
+bool Curl_meets_timecondition(struct SessionHandle *data, time_t timeofdoc);
+
+/* This sets up a forthcoming transfer */
+void
+Curl_setup_transfer (struct connectdata *data,
+ int sockindex, /* socket index to read from or -1 */
+ curl_off_t size, /* -1 if unknown at this point */
+ bool getheader, /* TRUE if header parsing is wanted */
+ curl_off_t *bytecountp, /* return number of bytes read */
+ int writesockindex, /* socket index to write to, it may
+ very well be the same we read from.
+ -1 disables */
+ curl_off_t *writecountp /* return number of bytes written */
+);
+
+long Curl_sleep_time(curl_off_t rate_bps, curl_off_t cur_rate_bps,
+ int pkt_size);
+
+#endif /* HEADER_CURL_TRANSFER_H */
+
diff --git a/libs/libcurl/src/url.c b/libs/libcurl/src/url.c
new file mode 100644
index 0000000000..c1672d08bc
--- /dev/null
+++ b/libs/libcurl/src/url.c
@@ -0,0 +1,5953 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+#ifdef HAVE_NETDB_H
+#include <netdb.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+#include <arpa/inet.h>
+#endif
+#ifdef HAVE_NET_IF_H
+#include <net/if.h>
+#endif
+#ifdef HAVE_SYS_IOCTL_H
+#include <sys/ioctl.h>
+#endif
+
+#ifdef HAVE_SYS_PARAM_H
+#include <sys/param.h>
+#endif
+
+#ifdef __VMS
+#include <in.h>
+#include <inet.h>
+#endif
+
+#ifndef HAVE_SOCKET
+#error "We can't compile without socket() support!"
+#endif
+
+#ifdef HAVE_LIMITS_H
+#include <limits.h>
+#endif
+
+#ifdef USE_LIBIDN
+#include <idna.h>
+#include <tld.h>
+#include <stringprep.h>
+#ifdef HAVE_IDN_FREE_H
+#include <idn-free.h>
+#else
+/* prototype from idn-free.h, not provided by libidn 0.4.5's make install! */
+void idn_free (void *ptr);
+#endif
+#ifndef HAVE_IDN_FREE
+/* if idn_free() was not found in this version of libidn use free() instead */
+#define idn_free(x) (free)(x)
+#endif
+#elif defined(USE_WIN32_IDN)
+/* prototype for curl_win32_idn_to_ascii() */
+int curl_win32_idn_to_ascii(const char *in, char **out);
+#endif /* USE_LIBIDN */
+
+#include "urldata.h"
+#include "netrc.h"
+
+#include "formdata.h"
+#include "sslgen.h"
+#include "hostip.h"
+#include "transfer.h"
+#include "sendf.h"
+#include "progress.h"
+#include "cookie.h"
+#include "strequal.h"
+#include "strerror.h"
+#include "escape.h"
+#include "strtok.h"
+#include "share.h"
+#include "content_encoding.h"
+#include "http_digest.h"
+#include "http_negotiate.h"
+#include "select.h"
+#include "multiif.h"
+#include "easyif.h"
+#include "speedcheck.h"
+#include "rawstr.h"
+#include "warnless.h"
+#include "non-ascii.h"
+#include "inet_pton.h"
+
+/* And now for the protocols */
+#include "ftp.h"
+#include "dict.h"
+#include "telnet.h"
+#include "tftp.h"
+#include "http.h"
+#include "file.h"
+#include "curl_ldap.h"
+#include "ssh.h"
+#include "imap.h"
+#include "url.h"
+#include "connect.h"
+#include "inet_ntop.h"
+#include "curl_ntlm.h"
+#include "curl_ntlm_wb.h"
+#include "socks.h"
+#include "curl_rtmp.h"
+#include "gopher.h"
+#include "http_proxy.h"
+#include "bundles.h"
+#include "conncache.h"
+#include "multihandle.h"
+#include "pipeline.h"
+#include "dotdot.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"
+
+/* Local static prototypes */
+static struct connectdata *
+find_oldest_idle_connection(struct SessionHandle *data);
+static struct connectdata *
+find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+ struct connectbundle *bundle);
+static void conn_free(struct connectdata *conn);
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke);
+static CURLcode do_init(struct connectdata *conn);
+static CURLcode parse_url_login(struct SessionHandle *data,
+ struct connectdata *conn,
+ char **userptr, char **passwdptr,
+ char **optionsptr);
+static CURLcode parse_login_details(const char *login, const size_t len,
+ char **userptr, char **passwdptr,
+ char **optionsptr);
+/*
+ * Protocol table.
+ */
+
+static const struct Curl_handler * const protocols[] = {
+
+#ifndef CURL_DISABLE_HTTP
+ &Curl_handler_http,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ &Curl_handler_https,
+#endif
+
+#ifndef CURL_DISABLE_FTP
+ &Curl_handler_ftp,
+#endif
+
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+ &Curl_handler_ftps,
+#endif
+
+#ifndef CURL_DISABLE_TELNET
+ &Curl_handler_telnet,
+#endif
+
+#ifndef CURL_DISABLE_DICT
+ &Curl_handler_dict,
+#endif
+
+#ifndef CURL_DISABLE_LDAP
+ &Curl_handler_ldap,
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+ &Curl_handler_ldaps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_FILE
+ &Curl_handler_file,
+#endif
+
+#ifndef CURL_DISABLE_TFTP
+ &Curl_handler_tftp,
+#endif
+
+#ifdef USE_LIBSSH2
+ &Curl_handler_scp,
+ &Curl_handler_sftp,
+#endif
+
+#ifndef CURL_DISABLE_IMAP
+ &Curl_handler_imap,
+#ifdef USE_SSL
+ &Curl_handler_imaps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_POP3
+ &Curl_handler_pop3,
+#ifdef USE_SSL
+ &Curl_handler_pop3s,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_SMTP
+ &Curl_handler_smtp,
+#ifdef USE_SSL
+ &Curl_handler_smtps,
+#endif
+#endif
+
+#ifndef CURL_DISABLE_RTSP
+ &Curl_handler_rtsp,
+#endif
+
+#ifndef CURL_DISABLE_GOPHER
+ &Curl_handler_gopher,
+#endif
+
+#ifdef USE_LIBRTMP
+ &Curl_handler_rtmp,
+ &Curl_handler_rtmpt,
+ &Curl_handler_rtmpe,
+ &Curl_handler_rtmpte,
+ &Curl_handler_rtmps,
+ &Curl_handler_rtmpts,
+#endif
+
+ (struct Curl_handler *) NULL
+};
+
+/*
+ * Dummy handler for undefined protocol schemes.
+ */
+
+static const struct Curl_handler Curl_handler_dummy = {
+ "<no protocol>", /* scheme */
+ ZERO_NULL, /* setup_connection */
+ ZERO_NULL, /* do_it */
+ ZERO_NULL, /* done */
+ ZERO_NULL, /* do_more */
+ ZERO_NULL, /* connect_it */
+ ZERO_NULL, /* connecting */
+ ZERO_NULL, /* doing */
+ ZERO_NULL, /* proto_getsock */
+ ZERO_NULL, /* doing_getsock */
+ ZERO_NULL, /* domore_getsock */
+ ZERO_NULL, /* perform_getsock */
+ ZERO_NULL, /* disconnect */
+ ZERO_NULL, /* readwrite */
+ 0, /* defport */
+ 0, /* protocol */
+ PROTOPT_NONE /* flags */
+};
+
+void Curl_freeset(struct SessionHandle *data)
+{
+ /* Free all dynamic strings stored in the data->set substructure. */
+ enum dupstring i;
+ for(i=(enum dupstring)0; i < STRING_LAST; i++)
+ Curl_safefree(data->set.str[i]);
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ data->change.referer = NULL;
+}
+
+static CURLcode setstropt(char **charp, char *s)
+{
+ /* Release the previous storage at `charp' and replace by a dynamic storage
+ copy of `s'. Return CURLE_OK or CURLE_OUT_OF_MEMORY. */
+
+ Curl_safefree(*charp);
+
+ if(s) {
+ s = strdup(s);
+
+ if(!s)
+ return CURLE_OUT_OF_MEMORY;
+
+ *charp = s;
+ }
+
+ return CURLE_OK;
+}
+
+static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp,
+ char **optionsp)
+{
+ CURLcode result = CURLE_OK;
+ char *user = NULL;
+ char *passwd = NULL;
+ char *options = NULL;
+
+ /* Parse the login details if specified. It not then we treat NULL as a hint
+ to clear the existing data */
+ if(option) {
+ result = parse_login_details(option, strlen(option),
+ (userp ? &user : NULL),
+ (passwdp ? &passwd : NULL),
+ (optionsp ? &options : NULL));
+ }
+
+ if(!result) {
+ /* Store the username part of option if required */
+ if(userp) {
+ if(!user && option && option[0] == ':') {
+ /* Allocate an empty string instead of returning NULL as user name */
+ user = strdup("");
+ if(!user)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ Curl_safefree(*userp);
+ *userp = user;
+ }
+
+ /* Store the password part of option if required */
+ if(passwdp) {
+ Curl_safefree(*passwdp);
+ *passwdp = passwd;
+ }
+
+ /* Store the options part of option if required */
+ if(optionsp) {
+ Curl_safefree(*optionsp);
+ *optionsp = options;
+ }
+ }
+
+ return result;
+}
+
+CURLcode Curl_dupset(struct SessionHandle *dst, struct SessionHandle *src)
+{
+ CURLcode r = CURLE_OK;
+ enum dupstring i;
+
+ /* Copy src->set into dst->set first, then deal with the strings
+ afterwards */
+ dst->set = src->set;
+
+ /* clear all string pointers first */
+ memset(dst->set.str, 0, STRING_LAST * sizeof(char *));
+
+ /* duplicate all strings */
+ for(i=(enum dupstring)0; i< STRING_LAST; i++) {
+ r = setstropt(&dst->set.str[i], src->set.str[i]);
+ if(r != CURLE_OK)
+ break;
+ }
+
+ /* If a failure occurred, freeing has to be performed externally. */
+ return r;
+}
+
+/*
+ * This is the internal function curl_easy_cleanup() calls. This should
+ * cleanup and free all resources associated with this sessionhandle.
+ *
+ * NOTE: if we ever add something that attempts to write to a socket or
+ * similar here, we must ignore SIGPIPE first. It is currently only done
+ * when curl_easy_perform() is invoked.
+ */
+
+CURLcode Curl_close(struct SessionHandle *data)
+{
+ struct Curl_multi *m;
+
+ if(!data)
+ return CURLE_OK;
+
+ Curl_expire(data, 0); /* shut off timers */
+
+ m = data->multi;
+
+ if(m)
+ /* This handle is still part of a multi handle, take care of this first
+ and detach this handle from there. */
+ curl_multi_remove_handle(data->multi, data);
+
+ if(data->multi_easy)
+ /* when curl_easy_perform() is used, it creates its own multi handle to
+ use and this is the one */
+ curl_multi_cleanup(data->multi_easy);
+
+ /* Destroy the timeout list that is held in the easy handle. It is
+ /normally/ done by curl_multi_remove_handle() but this is "just in
+ case" */
+ if(data->state.timeoutlist) {
+ Curl_llist_destroy(data->state.timeoutlist, NULL);
+ data->state.timeoutlist = NULL;
+ }
+
+ data->magic = 0; /* force a clear AFTER the possibly enforced removal from
+ the multi handle, since that function uses the magic
+ field! */
+
+ if(data->state.rangestringalloc)
+ free(data->state.range);
+
+ /* Free the pathbuffer */
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+
+ /* freed here just in case DONE wasn't called */
+ Curl_free_request_state(data);
+
+ /* Close down all open SSL info and sessions */
+ Curl_ssl_close_all(data);
+ Curl_safefree(data->state.first_host);
+ Curl_safefree(data->state.scratch);
+ Curl_ssl_free_certinfo(data);
+
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ data->change.referer = NULL;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ data->change.url = NULL;
+
+ Curl_safefree(data->state.headerbuff);
+
+ Curl_flush_cookies(data, 1);
+
+ Curl_digest_cleanup(data);
+
+ Curl_safefree(data->info.contenttype);
+ Curl_safefree(data->info.wouldredirect);
+
+ /* this destroys the channel and we cannot use it anymore after this */
+ Curl_resolver_cleanup(data->state.resolver);
+
+ Curl_convert_close(data);
+
+ /* No longer a dirty share, if it exists */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+ data->share->dirty--;
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ }
+
+ Curl_freeset(data);
+ free(data);
+ return CURLE_OK;
+}
+
+/*
+ * Initialize the UserDefined fields within a SessionHandle.
+ * This may be safely called on a new or existing SessionHandle.
+ */
+CURLcode Curl_init_userdefined(struct UserDefined *set)
+{
+ CURLcode res = CURLE_OK;
+
+ set->out = stdout; /* default output to stdout */
+ set->in = stdin; /* default input from stdin */
+ set->err = stderr; /* default stderr to stderr */
+
+ /* use fwrite as default function to store output */
+ set->fwrite_func = (curl_write_callback)fwrite;
+
+ /* use fread as default function to read input */
+ set->fread_func = (curl_read_callback)fread;
+ set->is_fread_set = 0;
+ set->is_fwrite_set = 0;
+
+ set->seek_func = ZERO_NULL;
+ set->seek_client = ZERO_NULL;
+
+ /* conversion callbacks for non-ASCII hosts */
+ set->convfromnetwork = ZERO_NULL;
+ set->convtonetwork = ZERO_NULL;
+ set->convfromutf8 = ZERO_NULL;
+
+ set->infilesize = -1; /* we don't know any size */
+ set->postfieldsize = -1; /* unknown size */
+ set->maxredirs = -1; /* allow any amount by default */
+
+ set->httpreq = HTTPREQ_GET; /* Default HTTP request */
+ set->rtspreq = RTSPREQ_OPTIONS; /* Default RTSP request */
+ set->ftp_use_epsv = TRUE; /* FTP defaults to EPSV operations */
+ set->ftp_use_eprt = TRUE; /* FTP defaults to EPRT operations */
+ set->ftp_use_pret = FALSE; /* mainly useful for drftpd servers */
+ set->ftp_filemethod = FTPFILE_MULTICWD;
+
+ set->dns_cache_timeout = 60; /* Timeout every 60 seconds by default */
+
+ /* Set the default size of the SSL session ID cache */
+ set->ssl.max_ssl_sessions = 5;
+
+ set->proxyport = CURL_DEFAULT_PROXY_PORT; /* from url.h */
+ set->proxytype = CURLPROXY_HTTP; /* defaults to HTTP proxy */
+ set->httpauth = CURLAUTH_BASIC; /* defaults to basic */
+ set->proxyauth = CURLAUTH_BASIC; /* defaults to basic */
+
+ /* make libcurl quiet by default: */
+ set->hide_progress = TRUE; /* CURLOPT_NOPROGRESS changes these */
+
+ /*
+ * libcurl 7.10 introduced SSL verification *by default*! This needs to be
+ * switched off unless wanted.
+ */
+ set->ssl.verifypeer = TRUE;
+ set->ssl.verifyhost = TRUE;
+#ifdef USE_TLS_SRP
+ set->ssl.authtype = CURL_TLSAUTH_NONE;
+#endif
+ set->ssh_auth_types = CURLSSH_AUTH_DEFAULT; /* defaults to any auth
+ type */
+ set->ssl.sessionid = TRUE; /* session ID caching enabled by default */
+
+ set->new_file_perms = 0644; /* Default permissions */
+ set->new_directory_perms = 0755; /* Default permissions */
+
+ /* for the *protocols fields we don't use the CURLPROTO_ALL convenience
+ define since we internally only use the lower 16 bits for the passed
+ in bitmask to not conflict with the private bits */
+ set->allowed_protocols = CURLPROTO_ALL;
+ set->redir_protocols =
+ CURLPROTO_ALL & ~(CURLPROTO_FILE|CURLPROTO_SCP); /* not FILE or SCP */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ /*
+ * disallow unprotected protection negotiation NEC reference implementation
+ * seem not to follow rfc1961 section 4.3/4.4
+ */
+ set->socks5_gssapi_nec = FALSE;
+ /* set default gssapi service name */
+ res = setstropt(&set->str[STRING_SOCKS5_GSSAPI_SERVICE],
+ (char *) CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE);
+ if(res != CURLE_OK)
+ return res;
+#endif
+
+ /* This is our preferred CA cert bundle/path since install time */
+#if defined(CURL_CA_BUNDLE)
+ res = setstropt(&set->str[STRING_SSL_CAFILE], (char *) CURL_CA_BUNDLE);
+#elif defined(CURL_CA_PATH)
+ res = setstropt(&set->str[STRING_SSL_CAPATH], (char *) CURL_CA_PATH);
+#endif
+
+ set->wildcardmatch = FALSE;
+ set->chunk_bgn = ZERO_NULL;
+ set->chunk_end = ZERO_NULL;
+
+ /* tcp keepalives are disabled by default, but provide reasonable values for
+ * the interval and idle times.
+ */
+ set->tcp_keepalive = FALSE;
+ set->tcp_keepintvl = 60;
+ set->tcp_keepidle = 60;
+
+ return res;
+}
+
+/**
+ * Curl_open()
+ *
+ * @param curl is a pointer to a sessionhandle pointer that gets set by this
+ * function.
+ * @return CURLcode
+ */
+
+CURLcode Curl_open(struct SessionHandle **curl)
+{
+ CURLcode res = CURLE_OK;
+ struct SessionHandle *data;
+ CURLcode status;
+
+ /* Very simple start-up: alloc the struct, init it with zeroes and return */
+ data = calloc(1, sizeof(struct SessionHandle));
+ if(!data) {
+ /* this is a very serious error */
+ DEBUGF(fprintf(stderr, "Error: calloc of SessionHandle failed\n"));
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ data->magic = CURLEASY_MAGIC_NUMBER;
+
+ status = Curl_resolver_init(&data->state.resolver);
+ if(status) {
+ DEBUGF(fprintf(stderr, "Error: resolver_init failed\n"));
+ free(data);
+ return status;
+ }
+
+ /* We do some initial setup here, all those fields that can't be just 0 */
+
+ data->state.headerbuff = malloc(HEADERSIZE);
+ if(!data->state.headerbuff) {
+ DEBUGF(fprintf(stderr, "Error: malloc of headerbuff failed\n"));
+ res = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+ res = Curl_init_userdefined(&data->set);
+
+ data->state.headersize=HEADERSIZE;
+
+ Curl_convert_init(data);
+
+ /* most recent connection is not yet defined */
+ data->state.lastconnect = NULL;
+
+ data->progress.flags |= PGRS_HIDE;
+ data->state.current_speed = -1; /* init to negative == impossible */
+
+ data->wildcard.state = CURLWC_INIT;
+ data->wildcard.filelist = NULL;
+ data->set.fnmatch = ZERO_NULL;
+ data->set.maxconnects = DEFAULT_CONNCACHE_SIZE; /* for easy handles */
+ }
+
+ if(res) {
+ Curl_resolver_cleanup(data->state.resolver);
+ if(data->state.headerbuff)
+ free(data->state.headerbuff);
+ Curl_freeset(data);
+ free(data);
+ data = NULL;
+ }
+ else
+ *curl = data;
+
+ return res;
+}
+
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+ va_list param)
+{
+ char *argptr;
+ CURLcode result = CURLE_OK;
+ long arg;
+#ifndef CURL_DISABLE_HTTP
+ curl_off_t bigsize;
+#endif
+
+ switch(option) {
+ case CURLOPT_DNS_CACHE_TIMEOUT:
+ data->set.dns_cache_timeout = va_arg(param, long);
+ break;
+ case CURLOPT_DNS_USE_GLOBAL_CACHE:
+ /* remember we want this enabled */
+ arg = va_arg(param, long);
+ data->set.global_dns_cache = (0 != arg)?TRUE:FALSE;
+ break;
+ case CURLOPT_SSL_CIPHER_LIST:
+ /* set a list of cipher we want to use in the SSL connection */
+ result = setstropt(&data->set.str[STRING_SSL_CIPHER_LIST],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RANDOM_FILE:
+ /*
+ * This is the path name to a file that contains random data to seed
+ * the random SSL stuff with. The file is only used for reading.
+ */
+ result = setstropt(&data->set.str[STRING_SSL_RANDOM_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_EGDSOCKET:
+ /*
+ * The Entropy Gathering Daemon socket pathname
+ */
+ result = setstropt(&data->set.str[STRING_SSL_EGDSOCKET],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_MAXCONNECTS:
+ /*
+ * Set the absolute number of maximum simultaneous alive connection that
+ * libcurl is allowed to have.
+ */
+ data->set.maxconnects = va_arg(param, long);
+ break;
+ case CURLOPT_FORBID_REUSE:
+ /*
+ * When this transfer is done, it must not be left to be reused by a
+ * subsequent transfer but shall be closed immediately.
+ */
+ data->set.reuse_forbid = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_FRESH_CONNECT:
+ /*
+ * This transfer shall not use a previously cached connection but
+ * should be made with a fresh new connect!
+ */
+ data->set.reuse_fresh = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_VERBOSE:
+ /*
+ * Verbose means infof() calls that give a lot of information about
+ * the connection and transfer procedures as well as internal choices.
+ */
+ data->set.verbose = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_HEADER:
+ /*
+ * Set to include the header in the general data output stream.
+ */
+ data->set.include_header = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_NOPROGRESS:
+ /*
+ * Shut off the internal supported progress meter
+ */
+ data->set.hide_progress = (0 != va_arg(param, long))?TRUE:FALSE;
+ if(data->set.hide_progress)
+ data->progress.flags |= PGRS_HIDE;
+ else
+ data->progress.flags &= ~PGRS_HIDE;
+ break;
+ case CURLOPT_NOBODY:
+ /*
+ * Do not include the body part in the output data stream.
+ */
+ data->set.opt_no_body = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_FAILONERROR:
+ /*
+ * Don't output the >=300 error code HTML-page, but instead only
+ * return error.
+ */
+ data->set.http_fail_on_error = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_UPLOAD:
+ case CURLOPT_PUT:
+ /*
+ * We want to sent data to the remote host. If this is HTTP, that equals
+ * using the PUT request.
+ */
+ data->set.upload = (0 != va_arg(param, long))?TRUE:FALSE;
+ if(data->set.upload) {
+ /* If this is HTTP, PUT is what's needed to "upload" */
+ data->set.httpreq = HTTPREQ_PUT;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ /* In HTTP, the opposite of upload is GET (unless NOBODY is true as
+ then this can be changed to HEAD later on) */
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+ case CURLOPT_FILETIME:
+ /*
+ * Try to get the file time of the remote document. The time will
+ * later (possibly) become available using curl_easy_getinfo().
+ */
+ data->set.get_filetime = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_FTP_CREATE_MISSING_DIRS:
+ /*
+ * An FTP option that modifies an upload to create missing directories on
+ * the server.
+ */
+ switch(va_arg(param, long)) {
+ case 0:
+ data->set.ftp_create_missing_dirs = 0;
+ break;
+ case 1:
+ data->set.ftp_create_missing_dirs = 1;
+ break;
+ case 2:
+ data->set.ftp_create_missing_dirs = 2;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+ case CURLOPT_SERVER_RESPONSE_TIMEOUT:
+ /*
+ * Option that specifies how quickly an server response must be obtained
+ * before it is considered failure. For pingpong protocols.
+ */
+ data->set.server_response_timeout = va_arg( param , long ) * 1000;
+ break;
+ case CURLOPT_TFTP_BLKSIZE:
+ /*
+ * TFTP option that specifies the block size to use for data transmission
+ */
+ data->set.tftp_blksize = va_arg(param, long);
+ break;
+ case CURLOPT_DIRLISTONLY:
+ /*
+ * An option that changes the command to one that asks for a list
+ * only, no file info details.
+ */
+ data->set.ftp_list_only = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_APPEND:
+ /*
+ * We want to upload and append to an existing file.
+ */
+ data->set.ftp_append = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_FTP_FILEMETHOD:
+ /*
+ * How do access files over FTP.
+ */
+ data->set.ftp_filemethod = (curl_ftpfile)va_arg(param, long);
+ break;
+ case CURLOPT_NETRC:
+ /*
+ * Parse the $HOME/.netrc file
+ */
+ data->set.use_netrc = (enum CURL_NETRC_OPTION)va_arg(param, long);
+ break;
+ case CURLOPT_NETRC_FILE:
+ /*
+ * Use this file instead of the $HOME/.netrc file
+ */
+ result = setstropt(&data->set.str[STRING_NETRC_FILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TRANSFERTEXT:
+ /*
+ * This option was previously named 'FTPASCII'. Renamed to work with
+ * more protocols than merely FTP.
+ *
+ * Transfer using ASCII (instead of BINARY).
+ */
+ data->set.prefer_ascii = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_TIMECONDITION:
+ /*
+ * Set HTTP time condition. This must be one of the defines in the
+ * curl/curl.h header file.
+ */
+ data->set.timecondition = (curl_TimeCond)va_arg(param, long);
+ break;
+ case CURLOPT_TIMEVALUE:
+ /*
+ * This is the value to compare with the remote document with the
+ * method set with CURLOPT_TIMECONDITION
+ */
+ data->set.timevalue = (time_t)va_arg(param, long);
+ break;
+ case CURLOPT_SSLVERSION:
+ /*
+ * Set explicit SSL version to try to connect with, as some SSL
+ * implementations are lame.
+ */
+ data->set.ssl.version = va_arg(param, long);
+ break;
+
+#ifndef CURL_DISABLE_HTTP
+ case CURLOPT_AUTOREFERER:
+ /*
+ * Switch on automatic referer that gets set if curl follows locations.
+ */
+ data->set.http_auto_referer = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_ACCEPT_ENCODING:
+ /*
+ * String to use at the value of Accept-Encoding header.
+ *
+ * If the encoding is set to "" we use an Accept-Encoding header that
+ * encompasses all the encodings we support.
+ * If the encoding is set to NULL we don't send an Accept-Encoding header
+ * and ignore an received Content-Encoding header.
+ *
+ */
+ argptr = va_arg(param, char *);
+ result = setstropt(&data->set.str[STRING_ENCODING],
+ (argptr && !*argptr)?
+ (char *) ALL_CONTENT_ENCODINGS: argptr);
+ break;
+
+ case CURLOPT_TRANSFER_ENCODING:
+ data->set.http_transfer_encoding = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FOLLOWLOCATION:
+ /*
+ * Follow Location: header hints on a HTTP-server.
+ */
+ data->set.http_follow_location = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_UNRESTRICTED_AUTH:
+ /*
+ * Send authentication (user+password) when following locations, even when
+ * hostname changed.
+ */
+ data->set.http_disable_hostname_check_before_authentication =
+ (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_MAXREDIRS:
+ /*
+ * The maximum amount of hops you allow curl to follow Location:
+ * headers. This should mostly be used to detect never-ending loops.
+ */
+ data->set.maxredirs = va_arg(param, long);
+ break;
+
+ case CURLOPT_POSTREDIR:
+ {
+ /*
+ * Set the behaviour of POST when redirecting
+ * CURL_REDIR_GET_ALL - POST is changed to GET after 301 and 302
+ * CURL_REDIR_POST_301 - POST is kept as POST after 301
+ * CURL_REDIR_POST_302 - POST is kept as POST after 302
+ * CURL_REDIR_POST_303 - POST is kept as POST after 303
+ * CURL_REDIR_POST_ALL - POST is kept as POST after 301, 302 and 303
+ * other - POST is kept as POST after 301 and 302
+ */
+ int postRedir = curlx_sltosi(va_arg(param, long));
+ data->set.keep_post = postRedir & CURL_REDIR_POST_ALL;
+ }
+ break;
+
+ case CURLOPT_POST:
+ /* Does this option serve a purpose anymore? Yes it does, when
+ CURLOPT_POSTFIELDS isn't used and the POST data is read off the
+ callback! */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_POST;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ else
+ data->set.httpreq = HTTPREQ_GET;
+ break;
+
+ case CURLOPT_COPYPOSTFIELDS:
+ /*
+ * A string with POST data. Makes curl HTTP POST. Even if it is NULL.
+ * If needed, CURLOPT_POSTFIELDSIZE must have been set prior to
+ * CURLOPT_COPYPOSTFIELDS and not altered later.
+ */
+ argptr = va_arg(param, char *);
+
+ if(!argptr || data->set.postfieldsize == -1)
+ result = setstropt(&data->set.str[STRING_COPYPOSTFIELDS], argptr);
+ else {
+ /*
+ * Check that requested length does not overflow the size_t type.
+ */
+
+ if((data->set.postfieldsize < 0) ||
+ ((sizeof(curl_off_t) != sizeof(size_t)) &&
+ (data->set.postfieldsize > (curl_off_t)((size_t)-1))))
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ char * p;
+
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+
+ /* Allocate even when size == 0. This satisfies the need of possible
+ later address compare to detect the COPYPOSTFIELDS mode, and
+ to mark that postfields is used rather than read function or
+ form data.
+ */
+ p = malloc((size_t)(data->set.postfieldsize?
+ data->set.postfieldsize:1));
+
+ if(!p)
+ result = CURLE_OUT_OF_MEMORY;
+ else {
+ if(data->set.postfieldsize)
+ memcpy(p, argptr, (size_t)data->set.postfieldsize);
+
+ data->set.str[STRING_COPYPOSTFIELDS] = p;
+ }
+ }
+ }
+
+ data->set.postfields = data->set.str[STRING_COPYPOSTFIELDS];
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDS:
+ /*
+ * Like above, but use static data instead of copying it.
+ */
+ data->set.postfields = va_arg(param, void *);
+ /* Release old copied data. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.httpreq = HTTPREQ_POST;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, long);
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_POSTFIELDSIZE_LARGE:
+ /*
+ * The size of the POSTFIELD data to prevent libcurl to do strlen() to
+ * figure it out. Enables binary posts.
+ */
+ bigsize = va_arg(param, curl_off_t);
+
+ if(data->set.postfieldsize < bigsize &&
+ data->set.postfields == data->set.str[STRING_COPYPOSTFIELDS]) {
+ /* Previous CURLOPT_COPYPOSTFIELDS is no longer valid. */
+ (void) setstropt(&data->set.str[STRING_COPYPOSTFIELDS], NULL);
+ data->set.postfields = NULL;
+ }
+
+ data->set.postfieldsize = bigsize;
+ break;
+
+ case CURLOPT_HTTPPOST:
+ /*
+ * Set to make us do HTTP POST
+ */
+ data->set.httppost = va_arg(param, struct curl_httppost *);
+ data->set.httpreq = HTTPREQ_POST_FORM;
+ data->set.opt_no_body = FALSE; /* this is implied */
+ break;
+
+ case CURLOPT_REFERER:
+ /*
+ * String to set in the HTTP Referer: field.
+ */
+ if(data->change.referer_alloc) {
+ Curl_safefree(data->change.referer);
+ data->change.referer_alloc = FALSE;
+ }
+ result = setstropt(&data->set.str[STRING_SET_REFERER],
+ va_arg(param, char *));
+ data->change.referer = data->set.str[STRING_SET_REFERER];
+ break;
+
+ case CURLOPT_USERAGENT:
+ /*
+ * String to use in the HTTP User-Agent field
+ */
+ result = setstropt(&data->set.str[STRING_USERAGENT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_HTTPHEADER:
+ /*
+ * Set a list with HTTP headers to use (or replace internals with)
+ */
+ data->set.headers = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_HTTP200ALIASES:
+ /*
+ * Set a list of aliases for HTTP 200 in response header
+ */
+ data->set.http200aliases = va_arg(param, struct curl_slist *);
+ break;
+
+#if !defined(CURL_DISABLE_COOKIES)
+ case CURLOPT_COOKIE:
+ /*
+ * Cookie string to send to the remote server in the request.
+ */
+ result = setstropt(&data->set.str[STRING_COOKIE],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_COOKIEFILE:
+ /*
+ * Set cookie file to read and parse. Can be used multiple times.
+ */
+ argptr = (char *)va_arg(param, void *);
+ if(argptr) {
+ struct curl_slist *cl;
+ /* append the cookie file name to the list of file names, and deal with
+ them later */
+ cl = curl_slist_append(data->change.cookielist, argptr);
+ if(!cl) {
+ curl_slist_free_all(data->change.cookielist);
+ data->change.cookielist = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->change.cookielist = cl; /* store the list for later use */
+ }
+ break;
+
+ case CURLOPT_COOKIEJAR:
+ /*
+ * Set cookie file name to dump all cookies to when we're done.
+ */
+ result = setstropt(&data->set.str[STRING_COOKIEJAR],
+ va_arg(param, char *));
+
+ /*
+ * Activate the cookie parser. This may or may not already
+ * have been made.
+ */
+ data->cookies = Curl_cookie_init(data, NULL, data->cookies,
+ data->set.cookiesession);
+ break;
+
+ case CURLOPT_COOKIESESSION:
+ /*
+ * Set this option to TRUE to start a new "cookie session". It will
+ * prevent the forthcoming read-cookies-from-file actions to accept
+ * cookies that are marked as being session cookies, as they belong to a
+ * previous session.
+ *
+ * In the original Netscape cookie spec, "session cookies" are cookies
+ * with no expire date set. RFC2109 describes the same action if no
+ * 'Max-Age' is set and RFC2965 includes the RFC2109 description and adds
+ * a 'Discard' action that can enforce the discard even for cookies that
+ * have a Max-Age.
+ *
+ * We run mostly with the original cookie spec, as hardly anyone implements
+ * anything else.
+ */
+ data->set.cookiesession = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_COOKIELIST:
+ argptr = va_arg(param, char *);
+
+ if(argptr == NULL)
+ break;
+
+ Curl_share_lock(data, CURL_LOCK_DATA_COOKIE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(Curl_raw_equal(argptr, "ALL")) {
+ /* clear all cookies */
+ Curl_cookie_clearall(data->cookies);
+ }
+ else if(Curl_raw_equal(argptr, "SESS")) {
+ /* clear session cookies */
+ Curl_cookie_clearsess(data->cookies);
+ }
+ else if(Curl_raw_equal(argptr, "FLUSH")) {
+ /* flush cookies to file */
+ Curl_flush_cookies(data, 0);
+ }
+ else {
+ if(!data->cookies)
+ /* if cookie engine was not running, activate it */
+ data->cookies = Curl_cookie_init(data, NULL, NULL, TRUE);
+
+ argptr = strdup(argptr);
+ if(!argptr) {
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ else {
+
+ if(checkprefix("Set-Cookie:", argptr))
+ /* HTTP Header format line */
+ Curl_cookie_add(data, data->cookies, TRUE, argptr + 11, NULL, NULL);
+
+ else
+ /* Netscape format line */
+ Curl_cookie_add(data, data->cookies, FALSE, argptr, NULL, NULL);
+
+ free(argptr);
+ }
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_COOKIE);
+
+ break;
+#endif /* CURL_DISABLE_COOKIES */
+
+ case CURLOPT_HTTPGET:
+ /*
+ * Set to force us do HTTP GET
+ */
+ if(va_arg(param, long)) {
+ data->set.httpreq = HTTPREQ_GET;
+ data->set.upload = FALSE; /* switch off upload */
+ data->set.opt_no_body = FALSE; /* this is implied */
+ }
+ break;
+
+ case CURLOPT_HTTP_VERSION:
+ /*
+ * This sets a requested HTTP version to be used. The value is one of
+ * the listed enums in curl/curl.h.
+ */
+ arg = va_arg(param, long);
+#ifndef USE_NGHTTP2
+ if(arg == CURL_HTTP_VERSION_2_0)
+ return CURLE_UNSUPPORTED_PROTOCOL;
+#endif
+ data->set.httpversion = arg;
+ break;
+
+ case CURLOPT_HTTPAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.httpauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authhost.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_HTTP_NEGOTIATE
+ auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or
+ WINDOWS_SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.httpauth = auth;
+ }
+ break;
+
+#endif /* CURL_DISABLE_HTTP */
+
+ case CURLOPT_CUSTOMREQUEST:
+ /*
+ * Set a custom string to use as request
+ */
+ result = setstropt(&data->set.str[STRING_CUSTOMREQUEST],
+ va_arg(param, char *));
+
+ /* we don't set
+ data->set.httpreq = HTTPREQ_CUSTOM;
+ here, we continue as if we were using the already set type
+ and this just changes the actual request keyword */
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_HTTPPROXYTUNNEL:
+ /*
+ * Tunnel operations through the proxy instead of normal proxy use
+ */
+ data->set.tunnel_thru_httpproxy = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_PROXYPORT:
+ /*
+ * Explicitly set HTTP proxy port number.
+ */
+ data->set.proxyport = va_arg(param, long);
+ break;
+
+ case CURLOPT_PROXYAUTH:
+ /*
+ * Set HTTP Authentication type BITMASK.
+ */
+ {
+ int bitcheck;
+ bool authbits;
+ unsigned long auth = va_arg(param, unsigned long);
+
+ if(auth == CURLAUTH_NONE) {
+ data->set.proxyauth = auth;
+ break;
+ }
+
+ /* the DIGEST_IE bit is only used to set a special marker, for all the
+ rest we need to handle it as normal DIGEST */
+ data->state.authproxy.iestyle = (auth & CURLAUTH_DIGEST_IE)?TRUE:FALSE;
+
+ if(auth & CURLAUTH_DIGEST_IE) {
+ auth |= CURLAUTH_DIGEST; /* set standard digest bit */
+ auth &= ~CURLAUTH_DIGEST_IE; /* unset ie digest bit */
+ }
+ /* switch off bits we can't support */
+#ifndef USE_NTLM
+ auth &= ~CURLAUTH_NTLM; /* no NTLM support */
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#elif !defined(NTLM_WB_ENABLED)
+ auth &= ~CURLAUTH_NTLM_WB; /* no NTLM_WB support */
+#endif
+#ifndef USE_HTTP_NEGOTIATE
+ auth &= ~CURLAUTH_GSSNEGOTIATE; /* no GSS-Negotiate without GSSAPI or
+ WINDOWS_SSPI */
+#endif
+
+ /* check if any auth bit lower than CURLAUTH_ONLY is still set */
+ bitcheck = 0;
+ authbits = FALSE;
+ while(bitcheck < 31) {
+ if(auth & (1UL << bitcheck++)) {
+ authbits = TRUE;
+ break;
+ }
+ }
+ if(!authbits)
+ return CURLE_NOT_BUILT_IN; /* no supported types left! */
+
+ data->set.proxyauth = auth;
+ }
+ break;
+
+ case CURLOPT_PROXY:
+ /*
+ * Set proxy server:port to use as HTTP proxy.
+ *
+ * If the proxy is set to "" we explicitly say that we don't want to use a
+ * proxy (even though there might be environment variables saying so).
+ *
+ * Setting it to NULL, means no proxy but allows the environment variables
+ * to decide for us.
+ */
+ result = setstropt(&data->set.str[STRING_PROXY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_PROXYTYPE:
+ /*
+ * Set proxy type. HTTP/HTTP_1_0/SOCKS4/SOCKS4a/SOCKS5/SOCKS5_HOSTNAME
+ */
+ data->set.proxytype = (curl_proxytype)va_arg(param, long);
+ break;
+
+ case CURLOPT_PROXY_TRANSFER_MODE:
+ /*
+ * set transfer mode (;type=<a|i>) when doing FTP via an HTTP proxy
+ */
+ switch (va_arg(param, long)) {
+ case 0:
+ data->set.proxy_transfer_mode = FALSE;
+ break;
+ case 1:
+ data->set.proxy_transfer_mode = TRUE;
+ break;
+ default:
+ /* reserve other values for future use */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+ break;
+#endif /* CURL_DISABLE_PROXY */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ case CURLOPT_SOCKS5_GSSAPI_SERVICE:
+ /*
+ * Set gssapi service name
+ */
+ result = setstropt(&data->set.str[STRING_SOCKS5_GSSAPI_SERVICE],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SOCKS5_GSSAPI_NEC:
+ /*
+ * set flag for nec socks5 support
+ */
+ data->set.socks5_gssapi_nec = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+#endif
+
+ case CURLOPT_WRITEHEADER:
+ /*
+ * Custom pointer to pass the header write callback function
+ */
+ data->set.writeheader = (void *)va_arg(param, void *);
+ break;
+ case CURLOPT_ERRORBUFFER:
+ /*
+ * Error buffer provided by the caller to get the human readable
+ * error string in.
+ */
+ data->set.errorbuffer = va_arg(param, char *);
+ break;
+ case CURLOPT_FILE:
+ /*
+ * FILE pointer to write to. Or possibly
+ * used as argument to the write callback.
+ */
+ data->set.out = va_arg(param, void *);
+ break;
+ case CURLOPT_FTPPORT:
+ /*
+ * Use FTP PORT, this also specifies which IP address to use
+ */
+ result = setstropt(&data->set.str[STRING_FTPPORT],
+ va_arg(param, char *));
+ data->set.ftp_use_port = (NULL != data->set.str[STRING_FTPPORT]) ?
+ TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPRT:
+ data->set.ftp_use_eprt = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_EPSV:
+ data->set.ftp_use_epsv = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_USE_PRET:
+ data->set.ftp_use_pret = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_SSL_CCC:
+ data->set.ftp_ccc = (curl_ftpccc)va_arg(param, long);
+ break;
+
+ case CURLOPT_FTP_SKIP_PASV_IP:
+ /*
+ * Enable or disable FTP_SKIP_PASV_IP, which will disable/enable the
+ * bypass of the IP address in PASV responses.
+ */
+ data->set.ftp_skip_ip = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_INFILE:
+ /*
+ * FILE pointer to read the file to be uploaded from. Or possibly
+ * used as argument to the read callback.
+ */
+ data->set.in = va_arg(param, void *);
+ break;
+ case CURLOPT_INFILESIZE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ data->set.infilesize = va_arg(param, long);
+ break;
+ case CURLOPT_INFILESIZE_LARGE:
+ /*
+ * If known, this should inform curl about the file size of the
+ * to-be-uploaded file.
+ */
+ data->set.infilesize = va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_LOW_SPEED_LIMIT:
+ /*
+ * The low speed limit that if transfers are below this for
+ * CURLOPT_LOW_SPEED_TIME, the transfer is aborted.
+ */
+ data->set.low_speed_limit=va_arg(param, long);
+ break;
+ case CURLOPT_MAX_SEND_SPEED_LARGE:
+ /*
+ * When transfer uploads are faster then CURLOPT_MAX_SEND_SPEED_LARGE
+ * bytes per second the transfer is throttled..
+ */
+ data->set.max_send_speed=va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_MAX_RECV_SPEED_LARGE:
+ /*
+ * When receiving data faster than CURLOPT_MAX_RECV_SPEED_LARGE bytes per
+ * second the transfer is throttled..
+ */
+ data->set.max_recv_speed=va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_LOW_SPEED_TIME:
+ /*
+ * The low speed time that if transfers are below the set
+ * CURLOPT_LOW_SPEED_LIMIT during this time, the transfer is aborted.
+ */
+ data->set.low_speed_time=va_arg(param, long);
+ break;
+ case CURLOPT_URL:
+ /*
+ * The URL to fetch.
+ */
+ if(data->change.url_alloc) {
+ /* the already set URL is allocated, free it first! */
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+ result = setstropt(&data->set.str[STRING_SET_URL],
+ va_arg(param, char *));
+ data->change.url = data->set.str[STRING_SET_URL];
+ break;
+ case CURLOPT_PORT:
+ /*
+ * The port number to use when getting the URL
+ */
+ data->set.use_port = va_arg(param, long);
+ break;
+ case CURLOPT_TIMEOUT:
+ /*
+ * The maximum time you allow curl to use for a single transfer
+ * operation.
+ */
+ data->set.timeout = va_arg(param, long) * 1000L;
+ break;
+
+ case CURLOPT_TIMEOUT_MS:
+ data->set.timeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT:
+ /*
+ * The maximum time you allow curl to use to connect.
+ */
+ data->set.connecttimeout = va_arg(param, long) * 1000L;
+ break;
+
+ case CURLOPT_CONNECTTIMEOUT_MS:
+ data->set.connecttimeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_ACCEPTTIMEOUT_MS:
+ /*
+ * The maximum time you allow curl to wait for server connect
+ */
+ data->set.accepttimeout = va_arg(param, long);
+ break;
+
+ case CURLOPT_USERPWD:
+ /*
+ * user:password;options to use in the operation
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_USERNAME],
+ &data->set.str[STRING_PASSWORD],
+ &data->set.str[STRING_OPTIONS]);
+ break;
+ case CURLOPT_USERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_USERNAME],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PASSWORD],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_XOAUTH2_BEARER:
+ /*
+ * XOAUTH2 bearer token to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_BEARER],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_POSTQUOTE:
+ /*
+ * List of RAW FTP commands to use after a transfer
+ */
+ data->set.postquote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_PREQUOTE:
+ /*
+ * List of RAW FTP commands to use prior to RETR (Wesley Laxton)
+ */
+ data->set.prequote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_QUOTE:
+ /*
+ * List of RAW FTP commands to use before a transfer
+ */
+ data->set.quote = va_arg(param, struct curl_slist *);
+ break;
+ case CURLOPT_RESOLVE:
+ /*
+ * List of NAME:[address] names to populate the DNS cache with
+ * Prefix the NAME with dash (-) to _remove_ the name from the cache.
+ *
+ * Names added with this API will remain in the cache until explicitly
+ * removed or the handle is cleaned up.
+ *
+ * This API can remove any name from the DNS cache, but only entries
+ * that aren't actually in use right now will be pruned immediately.
+ */
+ data->set.resolve = va_arg(param, struct curl_slist *);
+ data->change.resolve = data->set.resolve;
+ break;
+ case CURLOPT_PROGRESSFUNCTION:
+ /*
+ * Progress callback function
+ */
+ data->set.fprogress = va_arg(param, curl_progress_callback);
+ if(data->set.fprogress)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+ break;
+
+ case CURLOPT_XFERINFOFUNCTION:
+ /*
+ * Transfer info callback function
+ */
+ data->set.fxferinfo = va_arg(param, curl_xferinfo_callback);
+ if(data->set.fxferinfo)
+ data->progress.callback = TRUE; /* no longer internal */
+ else
+ data->progress.callback = FALSE; /* NULL enforces internal */
+
+ break;
+
+ case CURLOPT_PROGRESSDATA:
+ /*
+ * Custom client data to pass to the progress callback
+ */
+ data->set.progress_client = va_arg(param, void *);
+ break;
+
+#ifndef CURL_DISABLE_PROXY
+ case CURLOPT_PROXYUSERPWD:
+ /*
+ * user:password needed to use the proxy
+ */
+ result = setstropt_userpwd(va_arg(param, char *),
+ &data->set.str[STRING_PROXYUSERNAME],
+ &data->set.str[STRING_PROXYPASSWORD], NULL);
+ break;
+ case CURLOPT_PROXYUSERNAME:
+ /*
+ * authentication user name to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PROXYUSERNAME],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_PROXYPASSWORD:
+ /*
+ * authentication password to use in the operation
+ */
+ result = setstropt(&data->set.str[STRING_PROXYPASSWORD],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_NOPROXY:
+ /*
+ * proxy exception list
+ */
+ result = setstropt(&data->set.str[STRING_NOPROXY],
+ va_arg(param, char *));
+ break;
+#endif
+
+ case CURLOPT_RANGE:
+ /*
+ * What range of the file you want to transfer
+ */
+ result = setstropt(&data->set.str[STRING_SET_RANGE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_RESUME_FROM:
+ /*
+ * Resume transfer at the give file position
+ */
+ data->set.set_resume_from = va_arg(param, long);
+ break;
+ case CURLOPT_RESUME_FROM_LARGE:
+ /*
+ * Resume transfer at the give file position
+ */
+ data->set.set_resume_from = va_arg(param, curl_off_t);
+ break;
+ case CURLOPT_DEBUGFUNCTION:
+ /*
+ * stderr write callback.
+ */
+ data->set.fdebug = va_arg(param, curl_debug_callback);
+ /*
+ * if the callback provided is NULL, it'll use the default callback
+ */
+ break;
+ case CURLOPT_DEBUGDATA:
+ /*
+ * Set to a void * that should receive all error writes. This
+ * defaults to CURLOPT_STDERR for normal operations.
+ */
+ data->set.debugdata = va_arg(param, void *);
+ break;
+ case CURLOPT_STDERR:
+ /*
+ * Set to a FILE * that should receive all error writes. This
+ * defaults to stderr for normal operations.
+ */
+ data->set.err = va_arg(param, FILE *);
+ if(!data->set.err)
+ data->set.err = stderr;
+ break;
+ case CURLOPT_HEADERFUNCTION:
+ /*
+ * Set header write callback
+ */
+ data->set.fwrite_header = va_arg(param, curl_write_callback);
+ break;
+ case CURLOPT_WRITEFUNCTION:
+ /*
+ * Set data write callback
+ */
+ data->set.fwrite_func = va_arg(param, curl_write_callback);
+ if(!data->set.fwrite_func) {
+ data->set.is_fwrite_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fwrite_func = (curl_write_callback)fwrite;
+ }
+ else
+ data->set.is_fwrite_set = 1;
+ break;
+ case CURLOPT_READFUNCTION:
+ /*
+ * Read data callback
+ */
+ data->set.fread_func = va_arg(param, curl_read_callback);
+ if(!data->set.fread_func) {
+ data->set.is_fread_set = 0;
+ /* When set to NULL, reset to our internal default function */
+ data->set.fread_func = (curl_read_callback)fread;
+ }
+ else
+ data->set.is_fread_set = 1;
+ break;
+ case CURLOPT_SEEKFUNCTION:
+ /*
+ * Seek callback. Might be NULL.
+ */
+ data->set.seek_func = va_arg(param, curl_seek_callback);
+ break;
+ case CURLOPT_SEEKDATA:
+ /*
+ * Seek control callback. Might be NULL.
+ */
+ data->set.seek_client = va_arg(param, void *);
+ break;
+ case CURLOPT_CONV_FROM_NETWORK_FUNCTION:
+ /*
+ * "Convert from network encoding" callback
+ */
+ data->set.convfromnetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_TO_NETWORK_FUNCTION:
+ /*
+ * "Convert to network encoding" callback
+ */
+ data->set.convtonetwork = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_CONV_FROM_UTF8_FUNCTION:
+ /*
+ * "Convert from UTF-8 encoding" callback
+ */
+ data->set.convfromutf8 = va_arg(param, curl_conv_callback);
+ break;
+ case CURLOPT_IOCTLFUNCTION:
+ /*
+ * I/O control callback. Might be NULL.
+ */
+ data->set.ioctl_func = va_arg(param, curl_ioctl_callback);
+ break;
+ case CURLOPT_IOCTLDATA:
+ /*
+ * I/O control data pointer. Might be NULL.
+ */
+ data->set.ioctl_client = va_arg(param, void *);
+ break;
+ case CURLOPT_SSLCERT:
+ /*
+ * String that holds file name of the SSL certificate to use
+ */
+ result = setstropt(&data->set.str[STRING_CERT],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLCERTTYPE:
+ /*
+ * String that holds file type of the SSL certificate to use
+ */
+ result = setstropt(&data->set.str[STRING_CERT_TYPE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEY:
+ /*
+ * String that holds file name of the SSL key to use
+ */
+ result = setstropt(&data->set.str[STRING_KEY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLKEYTYPE:
+ /*
+ * String that holds file type of the SSL key to use
+ */
+ result = setstropt(&data->set.str[STRING_KEY_TYPE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_KEYPASSWD:
+ /*
+ * String that holds the SSL or SSH private key password.
+ */
+ result = setstropt(&data->set.str[STRING_KEY_PASSWD],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSLENGINE:
+ /*
+ * String that holds the SSL crypto engine.
+ */
+ argptr = va_arg(param, char *);
+ if(argptr && argptr[0])
+ result = Curl_ssl_set_engine(data, argptr);
+ break;
+
+ case CURLOPT_SSLENGINE_DEFAULT:
+ /*
+ * flag to set engine as default.
+ */
+ result = Curl_ssl_set_engine_default(data);
+ break;
+ case CURLOPT_CRLF:
+ /*
+ * Kludgy option to enable CRLF conversions. Subject for removal.
+ */
+ data->set.crlf = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_INTERFACE:
+ /*
+ * Set what interface or address/hostname to bind the socket to when
+ * performing an operation and thus what from-IP your connection will use.
+ */
+ result = setstropt(&data->set.str[STRING_DEVICE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_LOCALPORT:
+ /*
+ * Set what local port to bind the socket to when performing an operation.
+ */
+ data->set.localport = curlx_sltous(va_arg(param, long));
+ break;
+ case CURLOPT_LOCALPORTRANGE:
+ /*
+ * Set number of local ports to try, starting with CURLOPT_LOCALPORT.
+ */
+ data->set.localportrange = curlx_sltosi(va_arg(param, long));
+ break;
+ case CURLOPT_KRBLEVEL:
+ /*
+ * A string that defines the kerberos security level.
+ */
+ result = setstropt(&data->set.str[STRING_KRB_LEVEL],
+ va_arg(param, char *));
+ data->set.krb = (NULL != data->set.str[STRING_KRB_LEVEL])?TRUE:FALSE;
+ break;
+ case CURLOPT_GSSAPI_DELEGATION:
+ /*
+ * GSSAPI credential delegation
+ */
+ data->set.gssapi_delegation = va_arg(param, long);
+ break;
+ case CURLOPT_SSL_VERIFYPEER:
+ /*
+ * Enable peer SSL verifying.
+ */
+ data->set.ssl.verifypeer = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_SSL_VERIFYHOST:
+ /*
+ * Enable verification of the host name in the peer certificate
+ */
+ arg = va_arg(param, long);
+
+ /* Obviously people are not reading documentation and too many thought
+ this argument took a boolean when it wasn't and misused it. We thus ban
+ 1 as a sensible input and we warn about its use. Then we only have the
+ 2 action internally stored as TRUE. */
+
+ if(1 == arg) {
+ failf(data, "CURLOPT_SSL_VERIFYHOST no longer supports 1 as value!");
+ return CURLE_BAD_FUNCTION_ARGUMENT;
+ }
+
+ data->set.ssl.verifyhost = (0 != arg)?TRUE:FALSE;
+ break;
+#ifdef USE_SSLEAY
+ /* since these two options are only possible to use on an OpenSSL-
+ powered libcurl we #ifdef them on this condition so that libcurls
+ built against other SSL libs will return a proper error when trying
+ to set this option! */
+ case CURLOPT_SSL_CTX_FUNCTION:
+ /*
+ * Set a SSL_CTX callback
+ */
+ data->set.ssl.fsslctx = va_arg(param, curl_ssl_ctx_callback);
+ break;
+ case CURLOPT_SSL_CTX_DATA:
+ /*
+ * Set a SSL_CTX callback parameter pointer
+ */
+ data->set.ssl.fsslctxp = va_arg(param, void *);
+ break;
+#endif
+#if defined(USE_SSLEAY) || defined(USE_QSOSSL) || defined(USE_GSKIT)
+ case CURLOPT_CERTINFO:
+ data->set.ssl.certinfo = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+#endif
+ case CURLOPT_CAINFO:
+ /*
+ * Set CA info for SSL connection. Specify file name of the CA certificate
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CAFILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_CAPATH:
+ /*
+ * Set CA path info for SSL connection. Specify directory name of the CA
+ * certificates which have been prepared using openssl c_rehash utility.
+ */
+ /* This does not work on windows. */
+ result = setstropt(&data->set.str[STRING_SSL_CAPATH],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_CRLFILE:
+ /*
+ * Set CRL file info for SSL connection. Specify file name of the CRL
+ * to check certificates revocation
+ */
+ result = setstropt(&data->set.str[STRING_SSL_CRLFILE],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_ISSUERCERT:
+ /*
+ * Set Issuer certificate file
+ * to check certificates issuer
+ */
+ result = setstropt(&data->set.str[STRING_SSL_ISSUERCERT],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_TELNETOPTIONS:
+ /*
+ * Set a linked list of telnet options
+ */
+ data->set.telnet_options = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_BUFFERSIZE:
+ /*
+ * The application kindly asks for a differently sized receive buffer.
+ * If it seems reasonable, we'll use it.
+ */
+ data->set.buffer_size = va_arg(param, long);
+
+ if((data->set.buffer_size> (BUFSIZE -1 )) ||
+ (data->set.buffer_size < 1))
+ data->set.buffer_size = 0; /* huge internal default */
+
+ break;
+
+ case CURLOPT_NOSIGNAL:
+ /*
+ * The application asks not to set any signal() or alarm() handlers,
+ * even when using a timeout.
+ */
+ data->set.no_signal = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_SHARE:
+ {
+ struct Curl_share *set;
+ set = va_arg(param, struct Curl_share *);
+
+ /* disconnect from old share, if any */
+ if(data->share) {
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ if(data->dns.hostcachetype == HCACHE_SHARED) {
+ data->dns.hostcache = NULL;
+ data->dns.hostcachetype = HCACHE_NONE;
+ }
+
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies == data->cookies)
+ data->cookies = NULL;
+#endif
+
+ if(data->share->sslsession == data->state.session)
+ data->state.session = NULL;
+
+ data->share->dirty--;
+
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+ data->share = NULL;
+ }
+
+ /* use new share if it set */
+ data->share = set;
+ if(data->share) {
+
+ Curl_share_lock(data, CURL_LOCK_DATA_SHARE, CURL_LOCK_ACCESS_SINGLE);
+
+ data->share->dirty++;
+
+ if(data->share->hostcache) {
+ /* use shared host cache */
+ data->dns.hostcache = data->share->hostcache;
+ data->dns.hostcachetype = HCACHE_SHARED;
+ }
+#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_COOKIES)
+ if(data->share->cookies) {
+ /* use shared cookie list, first free own one if any */
+ if(data->cookies)
+ Curl_cookie_cleanup(data->cookies);
+ /* enable cookies since we now use a share that uses cookies! */
+ data->cookies = data->share->cookies;
+ }
+#endif /* CURL_DISABLE_HTTP */
+ if(data->share->sslsession) {
+ data->set.ssl.max_ssl_sessions = data->share->max_ssl_sessions;
+ data->state.session = data->share->sslsession;
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_SHARE);
+
+ }
+ /* check for host cache not needed,
+ * it will be done by curl_easy_perform */
+ }
+ break;
+
+ case CURLOPT_PRIVATE:
+ /*
+ * Set private data pointer.
+ */
+ data->set.private_data = va_arg(param, void *);
+ break;
+
+ case CURLOPT_MAXFILESIZE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ data->set.max_filesize = va_arg(param, long);
+ break;
+
+#ifdef USE_SSL
+ case CURLOPT_USE_SSL:
+ /*
+ * Make transfers attempt to use SSL/TLS.
+ */
+ data->set.use_ssl = (curl_usessl)va_arg(param, long);
+ break;
+
+ case CURLOPT_SSL_OPTIONS:
+ arg = va_arg(param, long);
+ data->set.ssl_enable_beast = arg&CURLSSLOPT_ALLOW_BEAST?TRUE:FALSE;
+ break;
+
+#endif
+ case CURLOPT_FTPSSLAUTH:
+ /*
+ * Set a specific auth for FTP-SSL transfers.
+ */
+ data->set.ftpsslauth = (curl_ftpauth)va_arg(param, long);
+ break;
+
+ case CURLOPT_IPRESOLVE:
+ data->set.ipver = va_arg(param, long);
+ break;
+
+ case CURLOPT_MAXFILESIZE_LARGE:
+ /*
+ * Set the maximum size of a file to download.
+ */
+ data->set.max_filesize = va_arg(param, curl_off_t);
+ break;
+
+ case CURLOPT_TCP_NODELAY:
+ /*
+ * Enable or disable TCP_NODELAY, which will disable/enable the Nagle
+ * algorithm
+ */
+ data->set.tcp_nodelay = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_ACCOUNT:
+ result = setstropt(&data->set.str[STRING_FTP_ACCOUNT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_IGNORE_CONTENT_LENGTH:
+ data->set.ignorecl = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_CONNECT_ONLY:
+ /*
+ * No data transfer, set up connection and let application use the socket
+ */
+ data->set.connect_only = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_FTP_ALTERNATIVE_TO_USER:
+ result = setstropt(&data->set.str[STRING_FTP_ALTERNATIVE_TO_USER],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SOCKOPTFUNCTION:
+ /*
+ * socket callback function: called after socket() but before connect()
+ */
+ data->set.fsockopt = va_arg(param, curl_sockopt_callback);
+ break;
+
+ case CURLOPT_SOCKOPTDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.sockopt_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_OPENSOCKETFUNCTION:
+ /*
+ * open/create socket callback function: called instead of socket(),
+ * before connect()
+ */
+ data->set.fopensocket = va_arg(param, curl_opensocket_callback);
+ break;
+
+ case CURLOPT_OPENSOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.opensocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_CLOSESOCKETFUNCTION:
+ /*
+ * close socket callback function: called instead of close()
+ * when shutting down a connection
+ */
+ data->set.fclosesocket = va_arg(param, curl_closesocket_callback);
+ break;
+
+ case CURLOPT_CLOSESOCKETDATA:
+ /*
+ * socket callback data pointer. Might be NULL.
+ */
+ data->set.closesocket_client = va_arg(param, void *);
+ break;
+
+ case CURLOPT_SSL_SESSIONID_CACHE:
+ data->set.ssl.sessionid = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+
+#ifdef USE_LIBSSH2
+ /* we only include SSH options if explicitly built to support SSH */
+ case CURLOPT_SSH_AUTH_TYPES:
+ data->set.ssh_auth_types = va_arg(param, long);
+ break;
+
+ case CURLOPT_SSH_PUBLIC_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa.pub file
+ */
+ result = setstropt(&data->set.str[STRING_SSH_PUBLIC_KEY],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_PRIVATE_KEYFILE:
+ /*
+ * Use this file instead of the $HOME/.ssh/id_dsa file
+ */
+ result = setstropt(&data->set.str[STRING_SSH_PRIVATE_KEY],
+ va_arg(param, char *));
+ break;
+ case CURLOPT_SSH_HOST_PUBLIC_KEY_MD5:
+ /*
+ * Option to allow for the MD5 of the host public key to be checked
+ * for validation purposes.
+ */
+ result = setstropt(&data->set.str[STRING_SSH_HOST_PUBLIC_KEY_MD5],
+ va_arg(param, char *));
+ break;
+#ifdef HAVE_LIBSSH2_KNOWNHOST_API
+ case CURLOPT_SSH_KNOWNHOSTS:
+ /*
+ * Store the file name to read known hosts from.
+ */
+ result = setstropt(&data->set.str[STRING_SSH_KNOWNHOSTS],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_SSH_KEYFUNCTION:
+ /* setting to NULL is fine since the ssh.c functions themselves will
+ then rever to use the internal default */
+ data->set.ssh_keyfunc = va_arg(param, curl_sshkeycallback);
+ break;
+
+ case CURLOPT_SSH_KEYDATA:
+ /*
+ * Custom client data to pass to the SSH keyfunc callback
+ */
+ data->set.ssh_keyfunc_userp = va_arg(param, void *);
+ break;
+#endif /* HAVE_LIBSSH2_KNOWNHOST_API */
+
+#endif /* USE_LIBSSH2 */
+
+ case CURLOPT_HTTP_TRANSFER_DECODING:
+ /*
+ * disable libcurl transfer encoding is used
+ */
+ data->set.http_te_skip = (0 == va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_HTTP_CONTENT_DECODING:
+ /*
+ * raw data passed to the application when content encoding is used
+ */
+ data->set.http_ce_skip = (0 == va_arg(param, long))?TRUE:FALSE;
+ break;
+
+ case CURLOPT_NEW_FILE_PERMS:
+ /*
+ * Uses these permissions instead of 0644
+ */
+ data->set.new_file_perms = va_arg(param, long);
+ break;
+
+ case CURLOPT_NEW_DIRECTORY_PERMS:
+ /*
+ * Uses these permissions instead of 0755
+ */
+ data->set.new_directory_perms = va_arg(param, long);
+ break;
+
+ case CURLOPT_ADDRESS_SCOPE:
+ /*
+ * We always get longs when passed plain numericals, but for this value we
+ * know that an unsigned int will always hold the value so we blindly
+ * typecast to this type
+ */
+ data->set.scope = curlx_sltoui(va_arg(param, long));
+ break;
+
+ case CURLOPT_PROTOCOLS:
+ /* set the bitmask for the protocols that are allowed to be used for the
+ transfer, which thus helps the app which takes URLs from users or other
+ external inputs and want to restrict what protocol(s) to deal
+ with. Defaults to CURLPROTO_ALL. */
+ data->set.allowed_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_REDIR_PROTOCOLS:
+ /* set the bitmask for the protocols that libcurl is allowed to follow to,
+ as a subset of the CURLOPT_PROTOCOLS ones. That means the protocol needs
+ to be set in both bitmasks to be allowed to get redirected to. Defaults
+ to all protocols except FILE and SCP. */
+ data->set.redir_protocols = va_arg(param, long);
+ break;
+
+ case CURLOPT_MAIL_FROM:
+ /* Set the SMTP mail originator */
+ result = setstropt(&data->set.str[STRING_MAIL_FROM],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_AUTH:
+ /* Set the SMTP auth originator */
+ result = setstropt(&data->set.str[STRING_MAIL_AUTH],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_MAIL_RCPT:
+ /* Set the list of mail recipients */
+ data->set.mail_rcpt = va_arg(param, struct curl_slist *);
+ break;
+
+ case CURLOPT_SASL_IR:
+ /* Enable/disable SASL initial response */
+ data->set.sasl_ir = (0 != va_arg(param, long)) ? TRUE : FALSE;
+ break;
+
+ case CURLOPT_RTSP_REQUEST:
+ {
+ /*
+ * Set the RTSP request method (OPTIONS, SETUP, PLAY, etc...)
+ * Would this be better if the RTSPREQ_* were just moved into here?
+ */
+ long curl_rtspreq = va_arg(param, long);
+ Curl_RtspReq rtspreq = RTSPREQ_NONE;
+ switch(curl_rtspreq) {
+ case CURL_RTSPREQ_OPTIONS:
+ rtspreq = RTSPREQ_OPTIONS;
+ break;
+
+ case CURL_RTSPREQ_DESCRIBE:
+ rtspreq = RTSPREQ_DESCRIBE;
+ break;
+
+ case CURL_RTSPREQ_ANNOUNCE:
+ rtspreq = RTSPREQ_ANNOUNCE;
+ break;
+
+ case CURL_RTSPREQ_SETUP:
+ rtspreq = RTSPREQ_SETUP;
+ break;
+
+ case CURL_RTSPREQ_PLAY:
+ rtspreq = RTSPREQ_PLAY;
+ break;
+
+ case CURL_RTSPREQ_PAUSE:
+ rtspreq = RTSPREQ_PAUSE;
+ break;
+
+ case CURL_RTSPREQ_TEARDOWN:
+ rtspreq = RTSPREQ_TEARDOWN;
+ break;
+
+ case CURL_RTSPREQ_GET_PARAMETER:
+ rtspreq = RTSPREQ_GET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_SET_PARAMETER:
+ rtspreq = RTSPREQ_SET_PARAMETER;
+ break;
+
+ case CURL_RTSPREQ_RECORD:
+ rtspreq = RTSPREQ_RECORD;
+ break;
+
+ case CURL_RTSPREQ_RECEIVE:
+ rtspreq = RTSPREQ_RECEIVE;
+ break;
+ default:
+ rtspreq = RTSPREQ_NONE;
+ }
+
+ data->set.rtspreq = rtspreq;
+ break;
+ }
+
+
+ case CURLOPT_RTSP_SESSION_ID:
+ /*
+ * Set the RTSP Session ID manually. Useful if the application is
+ * resuming a previously established RTSP session
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_SESSION_ID],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_STREAM_URI:
+ /*
+ * Set the Stream URI for the RTSP request. Unless the request is
+ * for generic server options, the application will need to set this.
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_STREAM_URI],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_TRANSPORT:
+ /*
+ * The content of the Transport: header for the RTSP request
+ */
+ result = setstropt(&data->set.str[STRING_RTSP_TRANSPORT],
+ va_arg(param, char *));
+ break;
+
+ case CURLOPT_RTSP_CLIENT_CSEQ:
+ /*
+ * Set the CSEQ number to issue for the next RTSP request. Useful if the
+ * application is resuming a previously broken connection. The CSEQ
+ * will increment from this new number henceforth.
+ */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_RTSP_SERVER_CSEQ:
+ /* Same as the above, but for server-initiated requests */
+ data->state.rtsp_next_client_CSeq = va_arg(param, long);
+ break;
+
+ case CURLOPT_INTERLEAVEDATA:
+ data->set.rtp_out = va_arg(param, void *);
+ break;
+ case CURLOPT_INTERLEAVEFUNCTION:
+ /* Set the user defined RTP write function */
+ data->set.fwrite_rtp = va_arg(param, curl_write_callback);
+ break;
+
+ case CURLOPT_WILDCARDMATCH:
+ data->set.wildcardmatch = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_CHUNK_BGN_FUNCTION:
+ data->set.chunk_bgn = va_arg(param, curl_chunk_bgn_callback);
+ break;
+ case CURLOPT_CHUNK_END_FUNCTION:
+ data->set.chunk_end = va_arg(param, curl_chunk_end_callback);
+ break;
+ case CURLOPT_FNMATCH_FUNCTION:
+ data->set.fnmatch = va_arg(param, curl_fnmatch_callback);
+ break;
+ case CURLOPT_CHUNK_DATA:
+ data->wildcard.customptr = va_arg(param, void *);
+ break;
+ case CURLOPT_FNMATCH_DATA:
+ data->set.fnmatch_data = va_arg(param, void *);
+ break;
+#ifdef USE_TLS_SRP
+ case CURLOPT_TLSAUTH_USERNAME:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_USERNAME],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_PASSWORD:
+ result = setstropt(&data->set.str[STRING_TLSAUTH_PASSWORD],
+ va_arg(param, char *));
+ if(data->set.str[STRING_TLSAUTH_USERNAME] && !data->set.ssl.authtype)
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP; /* default to SRP */
+ break;
+ case CURLOPT_TLSAUTH_TYPE:
+ if(strnequal((char *)va_arg(param, char *), "SRP", strlen("SRP")))
+ data->set.ssl.authtype = CURL_TLSAUTH_SRP;
+ else
+ data->set.ssl.authtype = CURL_TLSAUTH_NONE;
+ break;
+#endif
+ case CURLOPT_DNS_SERVERS:
+ result = Curl_set_dns_servers(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_INTERFACE:
+ result = Curl_set_dns_interface(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP4:
+ result = Curl_set_dns_local_ip4(data, va_arg(param, char *));
+ break;
+ case CURLOPT_DNS_LOCAL_IP6:
+ result = Curl_set_dns_local_ip6(data, va_arg(param, char *));
+ break;
+
+ case CURLOPT_TCP_KEEPALIVE:
+ data->set.tcp_keepalive = (0 != va_arg(param, long))?TRUE:FALSE;
+ break;
+ case CURLOPT_TCP_KEEPIDLE:
+ data->set.tcp_keepidle = va_arg(param, long);
+ break;
+ case CURLOPT_TCP_KEEPINTVL:
+ data->set.tcp_keepintvl = va_arg(param, long);
+ break;
+
+ default:
+ /* unknown tag and its companion, just ignore: */
+ result = CURLE_UNKNOWN_OPTION;
+ break;
+ }
+
+ return result;
+}
+
+static void conn_free(struct connectdata *conn)
+{
+ if(!conn)
+ return;
+
+ /* possible left-overs from the async name resolvers */
+ Curl_resolver_cancel(conn);
+
+ /* close the SSL stuff before we close any sockets since they will/may
+ write to the sockets */
+ Curl_ssl_close(conn, FIRSTSOCKET);
+ Curl_ssl_close(conn, SECONDARYSOCKET);
+
+ /* close possibly still open sockets */
+ if(CURL_SOCKET_BAD != conn->sock[SECONDARYSOCKET])
+ Curl_closesocket(conn, conn->sock[SECONDARYSOCKET]);
+ if(CURL_SOCKET_BAD != conn->sock[FIRSTSOCKET])
+ Curl_closesocket(conn, conn->sock[FIRSTSOCKET]);
+
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ Curl_ntlm_wb_cleanup(conn);
+#endif
+
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ Curl_safefree(conn->xoauth2_bearer);
+ Curl_safefree(conn->options);
+ Curl_safefree(conn->proxyuser);
+ Curl_safefree(conn->proxypasswd);
+ Curl_safefree(conn->allocptr.proxyuserpwd);
+ Curl_safefree(conn->allocptr.uagent);
+ Curl_safefree(conn->allocptr.userpwd);
+ Curl_safefree(conn->allocptr.accept_encoding);
+ Curl_safefree(conn->allocptr.te);
+ Curl_safefree(conn->allocptr.rangeline);
+ Curl_safefree(conn->allocptr.ref);
+ Curl_safefree(conn->allocptr.host);
+ Curl_safefree(conn->allocptr.cookiehost);
+ Curl_safefree(conn->allocptr.rtsp_transport);
+ Curl_safefree(conn->trailer);
+ Curl_safefree(conn->host.rawalloc); /* host name buffer */
+ Curl_safefree(conn->proxy.rawalloc); /* proxy name buffer */
+ Curl_safefree(conn->master_buffer);
+
+ Curl_llist_destroy(conn->send_pipe, NULL);
+ Curl_llist_destroy(conn->recv_pipe, NULL);
+
+ conn->send_pipe = NULL;
+ conn->recv_pipe = NULL;
+
+ Curl_safefree(conn->localdev);
+ Curl_free_ssl_config(&conn->ssl_config);
+
+ free(conn); /* free all the connection oriented data */
+}
+
+CURLcode Curl_disconnect(struct connectdata *conn, bool dead_connection)
+{
+ struct SessionHandle *data;
+ if(!conn)
+ return CURLE_OK; /* this is closed and fine already */
+ data = conn->data;
+
+ if(!data) {
+ DEBUGF(fprintf(stderr, "DISCONNECT without easy handle, ignoring\n"));
+ return CURLE_OK;
+ }
+
+ if(conn->dns_entry != NULL) {
+ Curl_resolv_unlock(data, conn->dns_entry);
+ conn->dns_entry = NULL;
+ }
+
+ Curl_hostcache_prune(data); /* kill old DNS cache entries */
+
+ {
+ int has_host_ntlm = (conn->ntlm.state != NTLMSTATE_NONE);
+ int has_proxy_ntlm = (conn->proxyntlm.state != NTLMSTATE_NONE);
+
+ /* Authentication data is a mix of connection-related and sessionhandle-
+ related stuff. NTLM is connection-related so when we close the shop
+ we shall forget. */
+
+ if(has_host_ntlm) {
+ data->state.authhost.done = FALSE;
+ data->state.authhost.picked =
+ data->state.authhost.want;
+ }
+
+ if(has_proxy_ntlm) {
+ data->state.authproxy.done = FALSE;
+ data->state.authproxy.picked =
+ data->state.authproxy.want;
+ }
+
+ if(has_host_ntlm || has_proxy_ntlm)
+ data->state.authproblem = FALSE;
+ }
+
+ /* Cleanup NTLM connection-related data */
+ Curl_http_ntlm_cleanup(conn);
+
+ /* Cleanup possible redirect junk */
+ if(data->req.newurl) {
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ }
+
+ if(conn->handler->disconnect)
+ /* This is set if protocol-specific cleanups should be made */
+ conn->handler->disconnect(conn, dead_connection);
+
+ /* unlink ourselves! */
+ infof(data, "Closing connection %ld\n", conn->connection_id);
+ Curl_conncache_remove_conn(data->state.conn_cache, conn);
+
+#if defined(USE_LIBIDN)
+ if(conn->host.encalloc)
+ idn_free(conn->host.encalloc); /* encoded host name buffer, must be freed
+ with idn_free() since this was allocated
+ by libidn */
+ if(conn->proxy.encalloc)
+ idn_free(conn->proxy.encalloc); /* encoded proxy name buffer, must be
+ freed with idn_free() since this was
+ allocated by libidn */
+#elif defined(USE_WIN32_IDN)
+ free(conn->host.encalloc); /* encoded host name buffer, must be freed with
+ idn_free() since this was allocated by
+ curl_win32_idn_to_ascii */
+ if(conn->proxy.encalloc)
+ free(conn->proxy.encalloc); /* encoded proxy name buffer, must be freed
+ with idn_free() since this was allocated by
+ curl_win32_idn_to_ascii */
+#endif
+
+ Curl_ssl_close(conn, FIRSTSOCKET);
+
+ /* Indicate to all handles on the pipe that we're dead */
+ if(Curl_multi_pipeline_enabled(data->multi)) {
+ signalPipeClose(conn->send_pipe, TRUE);
+ signalPipeClose(conn->recv_pipe, TRUE);
+ }
+
+ conn_free(conn);
+
+ Curl_speedinit(data);
+
+ return CURLE_OK;
+}
+
+/*
+ * This function should return TRUE if the socket is to be assumed to
+ * be dead. Most commonly this happens when the server has closed the
+ * connection due to inactivity.
+ */
+static bool SocketIsDead(curl_socket_t sock)
+{
+ int sval;
+ bool ret_val = TRUE;
+
+ sval = Curl_socket_ready(sock, CURL_SOCKET_BAD, 0);
+ if(sval == 0)
+ /* timeout */
+ ret_val = FALSE;
+
+ return ret_val;
+}
+
+static bool IsPipeliningPossible(const struct SessionHandle *handle,
+ const struct connectdata *conn)
+{
+ if((conn->handler->protocol & CURLPROTO_HTTP) &&
+ Curl_multi_pipeline_enabled(handle->multi) &&
+ (handle->set.httpreq == HTTPREQ_GET ||
+ handle->set.httpreq == HTTPREQ_HEAD) &&
+ handle->set.httpversion != CURL_HTTP_VERSION_1_0)
+ return TRUE;
+
+ return FALSE;
+}
+
+bool Curl_isPipeliningEnabled(const struct SessionHandle *handle)
+{
+ return Curl_multi_pipeline_enabled(handle->multi);
+}
+
+CURLcode Curl_addHandleToPipeline(struct SessionHandle *data,
+ struct curl_llist *pipeline)
+{
+ if(!Curl_llist_insert_next(pipeline, pipeline->tail, data))
+ return CURLE_OUT_OF_MEMORY;
+ infof(data, "Curl_addHandleToPipeline: length: %d\n", pipeline->size);
+ return CURLE_OK;
+}
+
+int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+ struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr;
+
+ curr = pipeline->head;
+ while(curr) {
+ if(curr->ptr == handle) {
+ Curl_llist_remove(pipeline, curr, NULL);
+ return 1; /* we removed a handle */
+ }
+ curr = curr->next;
+ }
+
+ return 0;
+}
+
+#if 0 /* this code is saved here as it is useful for debugging purposes */
+static void Curl_printPipeline(struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr;
+
+ curr = pipeline->head;
+ while(curr) {
+ struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+ infof(data, "Handle in pipeline: %s\n", data->state.path);
+ curr = curr->next;
+ }
+}
+#endif
+
+static struct SessionHandle* gethandleathead(struct curl_llist *pipeline)
+{
+ struct curl_llist_element *curr = pipeline->head;
+ if(curr) {
+ return (struct SessionHandle *) curr->ptr;
+ }
+
+ return NULL;
+}
+
+/* remove the specified connection from all (possible) pipelines and related
+ queues */
+void Curl_getoff_all_pipelines(struct SessionHandle *data,
+ struct connectdata *conn)
+{
+ bool recv_head = (conn->readchannel_inuse &&
+ (gethandleathead(conn->recv_pipe) == data)) ? TRUE : FALSE;
+
+ bool send_head = (conn->writechannel_inuse &&
+ (gethandleathead(conn->send_pipe) == data)) ? TRUE : FALSE;
+
+ if(Curl_removeHandleFromPipeline(data, conn->recv_pipe) && recv_head)
+ conn->readchannel_inuse = FALSE;
+ if(Curl_removeHandleFromPipeline(data, conn->send_pipe) && send_head)
+ conn->writechannel_inuse = FALSE;
+}
+
+static void signalPipeClose(struct curl_llist *pipeline, bool pipe_broke)
+{
+ struct curl_llist_element *curr;
+
+ if(!pipeline)
+ return;
+
+ curr = pipeline->head;
+ while(curr) {
+ struct curl_llist_element *next = curr->next;
+ struct SessionHandle *data = (struct SessionHandle *) curr->ptr;
+
+#ifdef DEBUGBUILD /* debug-only code */
+ if(data->magic != CURLEASY_MAGIC_NUMBER) {
+ /* MAJOR BADNESS */
+ infof(data, "signalPipeClose() found BAAD easy handle\n");
+ }
+#endif
+
+ if(pipe_broke)
+ data->state.pipe_broke = TRUE;
+ Curl_multi_handlePipeBreak(data);
+ Curl_llist_remove(pipeline, curr, NULL);
+ curr = next;
+ }
+}
+
+/*
+ * This function finds the connection in the connection
+ * cache that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+static struct connectdata *
+find_oldest_idle_connection(struct SessionHandle *data)
+{
+ struct conncache *bc = data->state.conn_cache;
+ struct curl_hash_iterator iter;
+ struct curl_llist_element *curr;
+ struct curl_hash_element *he;
+ long highscore=-1;
+ long score;
+ struct timeval now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectbundle *bundle;
+
+ now = Curl_tvnow();
+
+ Curl_hash_start_iterate(bc->hash, &iter);
+
+ he = Curl_hash_next_element(&iter);
+ while(he) {
+ struct connectdata *conn;
+
+ bundle = he->ptr;
+
+ curr = bundle->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+
+ if(!conn->inuse) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_tvdiff(now, conn->now);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ }
+ }
+ curr = curr->next;
+ }
+
+ he = Curl_hash_next_element(&iter);
+ }
+
+ return conn_candidate;
+}
+
+/*
+ * This function finds the connection in the connection
+ * bundle that has been unused for the longest time.
+ *
+ * Returns the pointer to the oldest idle connection, or NULL if none was
+ * found.
+ */
+static struct connectdata *
+find_oldest_idle_connection_in_bundle(struct SessionHandle *data,
+ struct connectbundle *bundle)
+{
+ struct curl_llist_element *curr;
+ long highscore=-1;
+ long score;
+ struct timeval now;
+ struct connectdata *conn_candidate = NULL;
+ struct connectdata *conn;
+
+ (void)data;
+
+ now = Curl_tvnow();
+
+ curr = bundle->conn_list->head;
+ while(curr) {
+ conn = curr->ptr;
+
+ if(!conn->inuse) {
+ /* Set higher score for the age passed since the connection was used */
+ score = Curl_tvdiff(now, conn->now);
+
+ if(score > highscore) {
+ highscore = score;
+ conn_candidate = conn;
+ }
+ }
+ curr = curr->next;
+ }
+
+ return conn_candidate;
+}
+
+/*
+ * Given one filled in connection struct (named needle), this function should
+ * detect if there already is one that has all the significant details
+ * exactly the same and thus should be used instead.
+ *
+ * If there is a match, this function returns TRUE - and has marked the
+ * connection as 'in-use'. It must later be called with ConnectionDone() to
+ * return back to 'idle' (unused) state.
+ *
+ * The force_reuse flag is set if the connection must be used, even if
+ * the pipelining strategy wants to open a new connection instead of reusing.
+ */
+static bool
+ConnectionExists(struct SessionHandle *data,
+ struct connectdata *needle,
+ struct connectdata **usethis,
+ bool *force_reuse)
+{
+ struct connectdata *check;
+ struct connectdata *chosen = 0;
+ bool canPipeline = IsPipeliningPossible(data, needle);
+ bool wantNTLM = (data->state.authhost.want==CURLAUTH_NTLM) ||
+ (data->state.authhost.want==CURLAUTH_NTLM_WB) ? TRUE : FALSE;
+ struct connectbundle *bundle;
+
+ *force_reuse = FALSE;
+
+ /* We can't pipe if the site is blacklisted */
+ if(canPipeline && Curl_pipeline_site_blacklisted(data, needle)) {
+ canPipeline = FALSE;
+ }
+
+ /* Look up the bundle with all the connections to this
+ particular host */
+ bundle = Curl_conncache_find_bundle(data->state.conn_cache,
+ needle->host.name);
+ if(bundle) {
+ size_t max_pipe_len = Curl_multi_max_pipeline_length(data->multi);
+ size_t best_pipe_len = max_pipe_len;
+ struct curl_llist_element *curr;
+
+ infof(data, "Found bundle for host %s: %p\n",
+ needle->host.name, (void *)bundle);
+
+ /* We can't pipe if we don't know anything about the server */
+ if(canPipeline && !bundle->server_supports_pipelining) {
+ infof(data, "Server doesn't support pipelining\n");
+ canPipeline = FALSE;
+ }
+
+ curr = bundle->conn_list->head;
+ while(curr) {
+ bool match = FALSE;
+ bool credentialsMatch = FALSE;
+ size_t pipeLen;
+
+ /*
+ * Note that if we use a HTTP proxy, we check connections to that
+ * proxy and not to the actual remote server.
+ */
+ check = curr->ptr;
+ curr = curr->next;
+
+ pipeLen = check->send_pipe->size + check->recv_pipe->size;
+
+ if(!pipeLen && !check->inuse) {
+ /* The check for a dead socket makes sense only if there are no
+ handles in pipeline and the connection isn't already marked in
+ use */
+ bool dead;
+ if(check->handler->protocol & CURLPROTO_RTSP)
+ /* RTSP is a special case due to RTP interleaving */
+ dead = Curl_rtsp_connisdead(check);
+ else
+ dead = SocketIsDead(check->sock[FIRSTSOCKET]);
+
+ if(dead) {
+ check->data = data;
+ infof(data, "Connection %ld seems to be dead!\n",
+ check->connection_id);
+
+ /* disconnect resources */
+ Curl_disconnect(check, /* dead_connection */ TRUE);
+ continue;
+ }
+ }
+
+ if(canPipeline) {
+ /* Make sure the pipe has only GET requests */
+ struct SessionHandle* sh = gethandleathead(check->send_pipe);
+ struct SessionHandle* rh = gethandleathead(check->recv_pipe);
+ if(sh) {
+ if(!IsPipeliningPossible(sh, check))
+ continue;
+ }
+ else if(rh) {
+ if(!IsPipeliningPossible(rh, check))
+ continue;
+ }
+ }
+ else {
+ if(pipeLen > 0) {
+ /* can only happen within multi handles, and means that another easy
+ handle is using this connection */
+ continue;
+ }
+
+ if(Curl_resolver_asynch()) {
+ /* ip_addr_str[0] is NUL only if the resolving of the name hasn't
+ completed yet and until then we don't re-use this connection */
+ if(!check->ip_addr_str[0]) {
+ infof(data,
+ "Connection #%ld is still name resolving, can't reuse\n",
+ check->connection_id);
+ continue;
+ }
+ }
+
+ if((check->sock[FIRSTSOCKET] == CURL_SOCKET_BAD) ||
+ check->bits.close) {
+ /* Don't pick a connection that hasn't connected yet or that is going
+ to get closed. */
+ infof(data, "Connection #%ld isn't open enough, can't reuse\n",
+ check->connection_id);
+#ifdef DEBUGBUILD
+ if(check->recv_pipe->size > 0) {
+ infof(data,
+ "BAD! Unconnected #%ld has a non-empty recv pipeline!\n",
+ check->connection_id);
+ }
+#endif
+ continue;
+ }
+ }
+
+ if((needle->handler->flags&PROTOPT_SSL) !=
+ (check->handler->flags&PROTOPT_SSL))
+ /* don't do mixed SSL and non-SSL connections */
+ if(!(needle->handler->protocol & check->handler->protocol))
+ /* except protocols that have been upgraded via TLS */
+ continue;
+
+ if(needle->handler->flags&PROTOPT_SSL) {
+ if((data->set.ssl.verifypeer != check->verifypeer) ||
+ (data->set.ssl.verifyhost != check->verifyhost))
+ continue;
+ }
+
+ if(needle->bits.proxy != check->bits.proxy)
+ /* don't do mixed proxy and non-proxy connections */
+ continue;
+
+ if(!canPipeline && check->inuse)
+ /* this request can't be pipelined but the checked connection is
+ already in use so we skip it */
+ continue;
+
+ if(needle->localdev || needle->localport) {
+ /* If we are bound to a specific local end (IP+port), we must not
+ re-use a random other one, although if we didn't ask for a
+ particular one we can reuse one that was bound.
+
+ This comparison is a bit rough and too strict. Since the input
+ parameters can be specified in numerous ways and still end up the
+ same it would take a lot of processing to make it really accurate.
+ Instead, this matching will assume that re-uses of bound connections
+ will most likely also re-use the exact same binding parameters and
+ missing out a few edge cases shouldn't hurt anyone very much.
+ */
+ if((check->localport != needle->localport) ||
+ (check->localportrange != needle->localportrange) ||
+ !check->localdev ||
+ !needle->localdev ||
+ strcmp(check->localdev, needle->localdev))
+ continue;
+ }
+
+ if((needle->handler->protocol & CURLPROTO_FTP) ||
+ ((needle->handler->protocol & CURLPROTO_HTTP) && wantNTLM)) {
+ /* This is FTP or HTTP+NTLM, verify that we're using the same name
+ and password as well */
+ if(!strequal(needle->user, check->user) ||
+ !strequal(needle->passwd, check->passwd)) {
+ /* one of them was different */
+ continue;
+ }
+ credentialsMatch = TRUE;
+ }
+
+ if(!needle->bits.httpproxy || needle->handler->flags&PROTOPT_SSL ||
+ (needle->bits.httpproxy && check->bits.httpproxy &&
+ needle->bits.tunnel_proxy && check->bits.tunnel_proxy &&
+ Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
+ (needle->port == check->port))) {
+ /* The requested connection does not use a HTTP proxy or it uses SSL or
+ it is a non-SSL protocol tunneled over the same http proxy name and
+ port number or it is a non-SSL protocol which is allowed to be
+ upgraded via TLS */
+
+ if((Curl_raw_equal(needle->handler->scheme, check->handler->scheme) ||
+ needle->handler->protocol & check->handler->protocol) &&
+ Curl_raw_equal(needle->host.name, check->host.name) &&
+ needle->remote_port == check->remote_port) {
+ if(needle->handler->flags & PROTOPT_SSL) {
+ /* This is a SSL connection so verify that we're using the same
+ SSL options as well */
+ if(!Curl_ssl_config_matches(&needle->ssl_config,
+ &check->ssl_config)) {
+ DEBUGF(infof(data,
+ "Connection #%ld has different SSL parameters, "
+ "can't reuse\n",
+ check->connection_id));
+ continue;
+ }
+ else if(check->ssl[FIRSTSOCKET].state != ssl_connection_complete) {
+ DEBUGF(infof(data,
+ "Connection #%ld has not started SSL connect, "
+ "can't reuse\n",
+ check->connection_id));
+ continue;
+ }
+ }
+ match = TRUE;
+ }
+ }
+ else { /* The requested needle connection is using a proxy,
+ is the checked one using the same host, port and type? */
+ if(check->bits.proxy &&
+ (needle->proxytype == check->proxytype) &&
+ (needle->bits.tunnel_proxy == check->bits.tunnel_proxy) &&
+ Curl_raw_equal(needle->proxy.name, check->proxy.name) &&
+ needle->port == check->port) {
+ /* This is the same proxy connection, use it! */
+ match = TRUE;
+ }
+ }
+
+ if(match) {
+ /* If we are looking for an NTLM connection, check if this is already
+ authenticating with the right credentials. If not, keep looking so
+ that we can reuse NTLM connections if possible. (Especially we
+ must not reuse the same connection if partway through
+ a handshake!) */
+ if(wantNTLM) {
+ if(credentialsMatch && check->ntlm.state != NTLMSTATE_NONE) {
+ chosen = check;
+
+ /* We must use this connection, no other */
+ *force_reuse = TRUE;
+ break;
+ }
+ else
+ continue;
+ }
+
+ if(canPipeline) {
+ /* We can pipeline if we want to. Let's continue looking for
+ the optimal connection to use, i.e the shortest pipe that is not
+ blacklisted. */
+
+ if(pipeLen == 0) {
+ /* We have the optimal connection. Let's stop looking. */
+ chosen = check;
+ break;
+ }
+
+ /* We can't use the connection if the pipe is full */
+ if(pipeLen >= max_pipe_len)
+ continue;
+
+ /* We can't use the connection if the pipe is penalized */
+ if(Curl_pipeline_penalized(data, check))
+ continue;
+
+ if(pipeLen < best_pipe_len) {
+ /* This connection has a shorter pipe so far. We'll pick this
+ and continue searching */
+ chosen = check;
+ best_pipe_len = pipeLen;
+ continue;
+ }
+ }
+ else {
+ /* We have found a connection. Let's stop searching. */
+ chosen = check;
+ break;
+ }
+ }
+ }
+ }
+
+ if(chosen) {
+ *usethis = chosen;
+ return TRUE; /* yes, we found one to use! */
+ }
+
+ return FALSE; /* no matching connecting exists */
+}
+
+/* Mark the connection as 'idle', or close it if the cache is full.
+ Returns TRUE if the connection is kept, or FALSE if it was closed. */
+static bool
+ConnectionDone(struct SessionHandle *data, struct connectdata *conn)
+{
+ /* data->multi->maxconnects can be negative, deal with it. */
+ size_t maxconnects =
+ (data->multi->maxconnects < 0) ? 0 : data->multi->maxconnects;
+ struct connectdata *conn_candidate = NULL;
+
+ /* Mark the current connection as 'unused' */
+ conn->inuse = FALSE;
+
+ if(maxconnects > 0 &&
+ data->state.conn_cache->num_connections > maxconnects) {
+ infof(data, "Connection cache is full, closing the oldest one.\n");
+
+ conn_candidate = find_oldest_idle_connection(data);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly */
+ conn_candidate->data = data;
+
+ /* the winner gets the honour of being disconnected */
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ }
+
+ return (conn_candidate == conn) ? FALSE : TRUE;
+}
+
+/*
+ * The given input connection struct pointer is to be stored in the connection
+ * cache. If the cache is already full, least interesting existing connection
+ * (if any) gets closed.
+ *
+ * The given connection should be unique. That must've been checked prior to
+ * this call.
+ */
+static CURLcode ConnectionStore(struct SessionHandle *data,
+ struct connectdata *conn)
+{
+ static int connection_id_counter = 0;
+
+ CURLcode result;
+
+ /* Assign a number to the connection for easier tracking in the log
+ output */
+ conn->connection_id = connection_id_counter++;
+
+ result = Curl_conncache_add_conn(data->state.conn_cache, conn);
+ if(result != CURLE_OK)
+ conn->connection_id = -1;
+
+ return result;
+}
+
+/* after a TCP connection to the proxy has been verified, this function does
+ the next magic step.
+
+ Note: this function's sub-functions call failf()
+
+*/
+CURLcode Curl_connected_proxy(struct connectdata *conn)
+{
+ if(!conn->bits.proxy)
+ return CURLE_OK;
+
+ switch(conn->proxytype) {
+#ifndef CURL_DISABLE_PROXY
+ case CURLPROXY_SOCKS5:
+ case CURLPROXY_SOCKS5_HOSTNAME:
+ return Curl_SOCKS5(conn->proxyuser, conn->proxypasswd,
+ conn->host.name, conn->remote_port,
+ FIRSTSOCKET, conn);
+
+ case CURLPROXY_SOCKS4:
+ return Curl_SOCKS4(conn->proxyuser, conn->host.name,
+ conn->remote_port, FIRSTSOCKET, conn, FALSE);
+
+ case CURLPROXY_SOCKS4A:
+ return Curl_SOCKS4(conn->proxyuser, conn->host.name,
+ conn->remote_port, FIRSTSOCKET, conn, TRUE);
+
+#endif /* CURL_DISABLE_PROXY */
+ case CURLPROXY_HTTP:
+ case CURLPROXY_HTTP_1_0:
+ /* do nothing here. handled later. */
+ break;
+ default:
+ break;
+ } /* switch proxytype */
+
+ return CURLE_OK;
+}
+
+static CURLcode ConnectPlease(struct SessionHandle *data,
+ struct connectdata *conn,
+ bool *connected)
+{
+ CURLcode result;
+ Curl_addrinfo *addr;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ char *hostname = conn->bits.proxy?conn->proxy.name:conn->host.name;
+
+ infof(data, "About to connect() to %s%s port %ld (#%ld)\n",
+ conn->bits.proxy?"proxy ":"",
+ hostname, conn->port, conn->connection_id);
+#else
+ (void)data;
+#endif
+
+ /*************************************************************
+ * Connect to server/proxy
+ *************************************************************/
+ result= Curl_connecthost(conn,
+ conn->dns_entry,
+ &conn->sock[FIRSTSOCKET],
+ &addr,
+ connected);
+ if(CURLE_OK == result) {
+ /* All is cool, we store the current information */
+ conn->ip_addr = addr;
+
+ if(*connected) {
+ result = Curl_connected_proxy(conn);
+ if(!result) {
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
+ Curl_pgrsTime(data, TIMER_CONNECT); /* connect done */
+ }
+ }
+ }
+
+ if(result)
+ *connected = FALSE; /* mark it as not connected */
+
+ return result;
+}
+
+/*
+ * verboseconnect() displays verbose information after a connect
+ */
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+void Curl_verboseconnect(struct connectdata *conn)
+{
+ if(conn->data->set.verbose)
+ infof(conn->data, "Connected to %s (%s) port %ld (#%ld)\n",
+ conn->bits.proxy ? conn->proxy.dispname : conn->host.dispname,
+ conn->ip_addr_str, conn->port, conn->connection_id);
+}
+#endif
+
+int Curl_protocol_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn->handler->proto_getsock)
+ return conn->handler->proto_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+int Curl_doing_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks)
+{
+ if(conn && conn->handler->doing_getsock)
+ return conn->handler->doing_getsock(conn, socks, numsocks);
+ return GETSOCK_BLANK;
+}
+
+/*
+ * We are doing protocol-specific connecting and this is being called over and
+ * over from the multi interface until the connection phase is done on
+ * protocol layer.
+ */
+
+CURLcode Curl_protocol_connecting(struct connectdata *conn,
+ bool *done)
+{
+ CURLcode result=CURLE_OK;
+
+ if(conn && conn->handler->connecting) {
+ *done = FALSE;
+ result = conn->handler->connecting(conn, done);
+ }
+ else
+ *done = TRUE;
+
+ return result;
+}
+
+/*
+ * We are DOING this is being called over and over from the multi interface
+ * until the DOING phase is done on protocol layer.
+ */
+
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done)
+{
+ CURLcode result=CURLE_OK;
+
+ if(conn && conn->handler->doing) {
+ *done = FALSE;
+ result = conn->handler->doing(conn, done);
+ }
+ else
+ *done = TRUE;
+
+ return result;
+}
+
+/*
+ * We have discovered that the TCP connection has been successful, we can now
+ * proceed with some action.
+ *
+ */
+CURLcode Curl_protocol_connect(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result=CURLE_OK;
+
+ *protocol_done = FALSE;
+
+ if(conn->bits.tcpconnect[FIRSTSOCKET] && conn->bits.protoconnstart) {
+ /* We already are connected, get back. This may happen when the connect
+ worked fine in the first call, like when we connect to a local server
+ or proxy. Note that we don't know if the protocol is actually done.
+
+ Unless this protocol doesn't have any protocol-connect callback, as
+ then we know we're done. */
+ if(!conn->handler->connecting)
+ *protocol_done = TRUE;
+
+ return CURLE_OK;
+ }
+
+ if(!conn->bits.protoconnstart) {
+
+ result = Curl_proxy_connect(conn);
+ if(result)
+ return result;
+
+ if(conn->bits.tunnel_proxy && conn->bits.httpproxy &&
+ (conn->tunnel_state[FIRSTSOCKET] != TUNNEL_COMPLETE))
+ /* when using an HTTP tunnel proxy, await complete tunnel establishment
+ before proceeding further. Return CURLE_OK so we'll be called again */
+ return CURLE_OK;
+
+ if(conn->handler->connect_it) {
+ /* is there a protocol-specific connect() procedure? */
+
+ /* Call the protocol-specific connect function */
+ result = conn->handler->connect_it(conn, protocol_done);
+ }
+ else
+ *protocol_done = TRUE;
+
+ /* it has started, possibly even completed but that knowledge isn't stored
+ in this bit! */
+ if(!result)
+ conn->bits.protoconnstart = TRUE;
+ }
+
+ return result; /* pass back status */
+}
+
+/*
+ * Helpers for IDNA convertions.
+ */
+static bool is_ASCII_name(const char *hostname)
+{
+ const unsigned char *ch = (const unsigned char*)hostname;
+
+ while(*ch) {
+ if(*ch++ & 0x80)
+ return FALSE;
+ }
+ return TRUE;
+}
+
+#ifdef USE_LIBIDN
+/*
+ * Check if characters in hostname is allowed in Top Level Domain.
+ */
+static bool tld_check_name(struct SessionHandle *data,
+ const char *ace_hostname)
+{
+ size_t err_pos;
+ char *uc_name = NULL;
+ int rc;
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+ const char *tld_errmsg = "<no msg>";
+#else
+ (void)data;
+#endif
+
+ /* Convert (and downcase) ACE-name back into locale's character set */
+ rc = idna_to_unicode_lzlz(ace_hostname, &uc_name, 0);
+ if(rc != IDNA_SUCCESS)
+ return FALSE;
+
+ rc = tld_check_lz(uc_name, &err_pos, NULL);
+#ifndef CURL_DISABLE_VERBOSE_STRINGS
+#ifdef HAVE_TLD_STRERROR
+ if(rc != TLD_SUCCESS)
+ tld_errmsg = tld_strerror((Tld_rc)rc);
+#endif
+ if(rc == TLD_INVALID)
+ infof(data, "WARNING: %s; pos %u = `%c'/0x%02X\n",
+ tld_errmsg, err_pos, uc_name[err_pos],
+ uc_name[err_pos] & 255);
+ else if(rc != TLD_SUCCESS)
+ infof(data, "WARNING: TLD check for %s failed; %s\n",
+ uc_name, tld_errmsg);
+#endif /* CURL_DISABLE_VERBOSE_STRINGS */
+ if(uc_name)
+ idn_free(uc_name);
+ if(rc != TLD_SUCCESS)
+ return FALSE;
+
+ return TRUE;
+}
+#endif
+
+/*
+ * Perform any necessary IDN conversion of hostname
+ */
+static void fix_hostname(struct SessionHandle *data,
+ struct connectdata *conn, struct hostname *host)
+{
+#ifndef USE_LIBIDN
+ (void)data;
+ (void)conn;
+#elif defined(CURL_DISABLE_VERBOSE_STRINGS)
+ (void)conn;
+#endif
+
+ /* set the name we use to display the host name */
+ host->dispname = host->name;
+ if(!is_ASCII_name(host->name)) {
+#ifdef USE_LIBIDN
+ /*************************************************************
+ * Check name for non-ASCII and convert hostname to ACE form.
+ *************************************************************/
+ if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+ char *ace_hostname = NULL;
+ int rc = idna_to_ascii_lz(host->name, &ace_hostname, 0);
+ infof (data, "Input domain encoded as `%s'\n",
+ stringprep_locale_charset ());
+ if(rc != IDNA_SUCCESS)
+ infof(data, "Failed to convert %s to ACE; %s\n",
+ host->name, Curl_idn_strerror(conn,rc));
+ else {
+ /* tld_check_name() displays a warning if the host name contains
+ "illegal" characters for this TLD */
+ (void)tld_check_name(data, ace_hostname);
+
+ host->encalloc = ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+ }
+#elif defined(USE_WIN32_IDN)
+ /*************************************************************
+ * Check name for non-ASCII and convert hostname to ACE form.
+ *************************************************************/
+ char *ace_hostname = NULL;
+ int rc = curl_win32_idn_to_ascii(host->name, &ace_hostname);
+ if(rc == 0)
+ infof(data, "Failed to convert %s to ACE;\n",
+ host->name);
+ else {
+ host->encalloc = ace_hostname;
+ /* change the name pointer to point to the encoded hostname */
+ host->name = host->encalloc;
+ }
+#else
+ infof(data, "IDN support not present, can't parse Unicode domains\n");
+#endif
+ }
+}
+
+static void llist_dtor(void *user, void *element)
+{
+ (void)user;
+ (void)element;
+ /* Do nothing */
+}
+
+/*
+ * Allocate and initialize a new connectdata object.
+ */
+static struct connectdata *allocate_conn(struct SessionHandle *data)
+{
+ struct connectdata *conn = calloc(1, sizeof(struct connectdata));
+ if(!conn)
+ return NULL;
+
+ conn->handler = &Curl_handler_dummy; /* Be sure we have a handler defined
+ already from start to avoid NULL
+ situations and checks */
+
+ /* and we setup a few fields in case we end up actually using this struct */
+
+ conn->sock[FIRSTSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->sock[SECONDARYSOCKET] = CURL_SOCKET_BAD; /* no file descriptor */
+ conn->connection_id = -1; /* no ID */
+ conn->port = -1; /* unknown at this point */
+
+ /* Default protocol-independent behavior doesn't support persistent
+ connections, so we set this to force-close. Protocols that support
+ this need to set this to FALSE in their "curl_do" functions. */
+ conn->bits.close = TRUE;
+
+ /* Store creation time to help future close decision making */
+ conn->created = Curl_tvnow();
+
+ conn->data = data; /* Setup the association between this connection
+ and the SessionHandle */
+
+ conn->proxytype = data->set.proxytype; /* type */
+
+#ifdef CURL_DISABLE_PROXY
+
+ conn->bits.proxy = FALSE;
+ conn->bits.httpproxy = FALSE;
+ conn->bits.proxy_user_passwd = FALSE;
+ conn->bits.tunnel_proxy = FALSE;
+
+#else /* CURL_DISABLE_PROXY */
+
+ /* note that these two proxy bits are now just on what looks to be
+ requested, they may be altered down the road */
+ conn->bits.proxy = (data->set.str[STRING_PROXY] &&
+ *data->set.str[STRING_PROXY])?TRUE:FALSE;
+ conn->bits.httpproxy = (conn->bits.proxy &&
+ (conn->proxytype == CURLPROXY_HTTP ||
+ conn->proxytype == CURLPROXY_HTTP_1_0))?TRUE:FALSE;
+ conn->bits.proxy_user_passwd =
+ (NULL != data->set.str[STRING_PROXYUSERNAME])?TRUE:FALSE;
+ conn->bits.tunnel_proxy = data->set.tunnel_thru_httpproxy;
+
+#endif /* CURL_DISABLE_PROXY */
+
+ conn->bits.user_passwd = (NULL != data->set.str[STRING_USERNAME])?TRUE:FALSE;
+ conn->bits.ftp_use_epsv = data->set.ftp_use_epsv;
+ conn->bits.ftp_use_eprt = data->set.ftp_use_eprt;
+
+ conn->verifypeer = data->set.ssl.verifypeer;
+ conn->verifyhost = data->set.ssl.verifyhost;
+
+ conn->ip_version = data->set.ipver;
+
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ conn->ntlm_auth_hlpr_socket = CURL_SOCKET_BAD;
+ conn->ntlm_auth_hlpr_pid = 0;
+ conn->challenge_header = NULL;
+ conn->response_header = NULL;
+#endif
+
+ if(Curl_multi_pipeline_enabled(data->multi) &&
+ !conn->master_buffer) {
+ /* Allocate master_buffer to be used for pipelining */
+ conn->master_buffer = calloc(BUFSIZE, sizeof (char));
+ if(!conn->master_buffer)
+ goto error;
+ }
+
+ /* Initialize the pipeline lists */
+ conn->send_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+ conn->recv_pipe = Curl_llist_alloc((curl_llist_dtor) llist_dtor);
+ if(!conn->send_pipe || !conn->recv_pipe)
+ goto error;
+
+#ifdef HAVE_GSSAPI
+ conn->data_prot = PROT_CLEAR;
+#endif
+
+ /* Store the local bind parameters that will be used for this connection */
+ if(data->set.str[STRING_DEVICE]) {
+ conn->localdev = strdup(data->set.str[STRING_DEVICE]);
+ if(!conn->localdev)
+ goto error;
+ }
+ conn->localportrange = data->set.localportrange;
+ conn->localport = data->set.localport;
+
+ /* the close socket stuff needs to be copied to the connection struct as
+ it may live on without (this specific) SessionHandle */
+ conn->fclosesocket = data->set.fclosesocket;
+ conn->closesocket_client = data->set.closesocket_client;
+
+ return conn;
+ error:
+
+ Curl_llist_destroy(conn->send_pipe, NULL);
+ Curl_llist_destroy(conn->recv_pipe, NULL);
+
+ conn->send_pipe = NULL;
+ conn->recv_pipe = NULL;
+
+ Curl_safefree(conn->master_buffer);
+ Curl_safefree(conn->localdev);
+ Curl_safefree(conn);
+ return NULL;
+}
+
+static CURLcode findprotocol(struct SessionHandle *data,
+ struct connectdata *conn,
+ const char *protostr)
+{
+ const struct Curl_handler * const *pp;
+ const struct Curl_handler *p;
+
+ /* Scan protocol handler table and match against 'protostr' to set a few
+ variables based on the URL. Now that the handler may be changed later
+ when the protocol specific setup function is called. */
+ for(pp = protocols; (p = *pp) != NULL; pp++) {
+ if(Curl_raw_equal(p->scheme, protostr)) {
+ /* Protocol found in table. Check if allowed */
+ if(!(data->set.allowed_protocols & p->protocol))
+ /* nope, get out */
+ break;
+
+ /* it is allowed for "normal" request, now do an extra check if this is
+ the result of a redirect */
+ if(data->state.this_is_a_follow &&
+ !(data->set.redir_protocols & p->protocol))
+ /* nope, get out */
+ break;
+
+ /* Perform setup complement if some. */
+ conn->handler = conn->given = p;
+
+ /* 'port' and 'remote_port' are set in setup_connection_internals() */
+ return CURLE_OK;
+ }
+ }
+
+
+ /* The protocol was not found in the table, but we don't have to assign it
+ to anything since it is already assigned to a dummy-struct in the
+ create_conn() function when the connectdata struct is allocated. */
+ failf(data, "Protocol %s not supported or disabled in " LIBCURL_NAME,
+ protostr);
+
+ return CURLE_UNSUPPORTED_PROTOCOL;
+}
+
+/*
+ * Parse URL and fill in the relevant members of the connection struct.
+ */
+static CURLcode parseurlandfillconn(struct SessionHandle *data,
+ struct connectdata *conn,
+ bool *prot_missing,
+ char **userp, char **passwdp,
+ char **optionsp)
+{
+ char *at;
+ char *fragment;
+ char *path = data->state.path;
+ char *query;
+ int rc;
+ char protobuf[16];
+ const char *protop;
+ CURLcode result;
+ bool rebuild_url = FALSE;
+
+ *prot_missing = FALSE;
+
+ /*************************************************************
+ * Parse the URL.
+ *
+ * We need to parse the url even when using the proxy, because we will need
+ * the hostname and port in case we are trying to SSL connect through the
+ * proxy -- and we don't know if we will need to use SSL until we parse the
+ * url ...
+ ************************************************************/
+ if((2 == sscanf(data->change.url, "%15[^:]:%[^\n]",
+ protobuf, path)) &&
+ Curl_raw_equal(protobuf, "file")) {
+ if(path[0] == '/' && path[1] == '/') {
+ /* Allow omitted hostname (e.g. file:/<path>). This is not strictly
+ * speaking a valid file: URL by RFC 1738, but treating file:/<path> as
+ * file://localhost/<path> is similar to how other schemes treat missing
+ * hostnames. See RFC 1808. */
+
+ /* This cannot be done with strcpy() in a portable manner, since the
+ memory areas overlap! */
+ memmove(path, path + 2, strlen(path + 2)+1);
+ }
+ /*
+ * we deal with file://<host>/<path> differently since it supports no
+ * hostname other than "localhost" and "127.0.0.1", which is unique among
+ * the URL protocols specified in RFC 1738
+ */
+ if(path[0] != '/') {
+ /* the URL included a host name, we ignore host names in file:// URLs
+ as the standards don't define what to do with them */
+ char *ptr=strchr(path, '/');
+ if(ptr) {
+ /* there was a slash present
+
+ RFC1738 (section 3.1, page 5) says:
+
+ The rest of the locator consists of data specific to the scheme,
+ and is known as the "url-path". It supplies the details of how the
+ specified resource can be accessed. Note that the "/" between the
+ host (or port) and the url-path is NOT part of the url-path.
+
+ As most agents use file://localhost/foo to get '/foo' although the
+ slash preceding foo is a separator and not a slash for the path,
+ a URL as file://localhost//foo must be valid as well, to refer to
+ the same file with an absolute path.
+ */
+
+ if(ptr[1] && ('/' == ptr[1]))
+ /* if there was two slashes, we skip the first one as that is then
+ used truly as a separator */
+ ptr++;
+
+ /* This cannot be made with strcpy, as the memory chunks overlap! */
+ memmove(path, ptr, strlen(ptr)+1);
+ }
+ }
+
+ protop = "file"; /* protocol string */
+ }
+ else {
+ /* clear path */
+ path[0]=0;
+
+ if(2 > sscanf(data->change.url,
+ "%15[^\n:]://%[^\n/?]%[^\n]",
+ protobuf,
+ conn->host.name, path)) {
+
+ /*
+ * The URL was badly formatted, let's try the browser-style _without_
+ * protocol specified like 'http://'.
+ */
+ rc = sscanf(data->change.url, "%[^\n/?]%[^\n]", conn->host.name, path);
+ if(1 > rc) {
+ /*
+ * We couldn't even get this format.
+ * djgpp 2.04 has a sscanf() bug where 'conn->host.name' is
+ * assigned, but the return value is EOF!
+ */
+#if defined(__DJGPP__) && (DJGPP_MINOR == 4)
+ if(!(rc == -1 && *conn->host.name))
+#endif
+ {
+ failf(data, "<url> malformed");
+ return CURLE_URL_MALFORMAT;
+ }
+ }
+
+ /*
+ * Since there was no protocol part specified, we guess what protocol it
+ * is based on the first letters of the server name.
+ */
+
+ /* Note: if you add a new protocol, please update the list in
+ * lib/version.c too! */
+
+ if(checkprefix("FTP.", conn->host.name))
+ protop = "ftp";
+ else if(checkprefix("DICT.", conn->host.name))
+ protop = "DICT";
+ else if(checkprefix("LDAP.", conn->host.name))
+ protop = "LDAP";
+ else if(checkprefix("IMAP.", conn->host.name))
+ protop = "IMAP";
+ else if(checkprefix("SMTP.", conn->host.name))
+ protop = "smtp";
+ else if(checkprefix("POP3.", conn->host.name))
+ protop = "pop3";
+ else {
+ protop = "http";
+ }
+
+ *prot_missing = TRUE; /* not given in URL */
+ }
+ else
+ protop = protobuf;
+ }
+
+ /* We search for '?' in the host name (but only on the right side of a
+ * @-letter to allow ?-letters in username and password) to handle things
+ * like http://example.com?param= (notice the missing '/').
+ */
+ at = strchr(conn->host.name, '@');
+ if(at)
+ query = strchr(at+1, '?');
+ else
+ query = strchr(conn->host.name, '?');
+
+ if(query) {
+ /* We must insert a slash before the '?'-letter in the URL. If the URL had
+ a slash after the '?', that is where the path currently begins and the
+ '?string' is still part of the host name.
+
+ We must move the trailing part from the host name and put it first in
+ the path. And have it all prefixed with a slash.
+ */
+
+ size_t hostlen = strlen(query);
+ size_t pathlen = strlen(path);
+
+ /* move the existing path plus the zero byte forward, to make room for
+ the host-name part */
+ memmove(path+hostlen+1, path, pathlen+1);
+
+ /* now copy the trailing host part in front of the existing path */
+ memcpy(path+1, query, hostlen);
+
+ path[0]='/'; /* prepend the missing slash */
+ rebuild_url = TRUE;
+
+ *query=0; /* now cut off the hostname at the ? */
+ }
+ else if(!path[0]) {
+ /* if there's no path set, use a single slash */
+ strcpy(path, "/");
+ rebuild_url = TRUE;
+ }
+
+ /* If the URL is malformatted (missing a '/' after hostname before path) we
+ * insert a slash here. The only letter except '/' we accept to start a path
+ * is '?'.
+ */
+ if(path[0] == '?') {
+ /* We need this function to deal with overlapping memory areas. We know
+ that the memory area 'path' points to is 'urllen' bytes big and that
+ is bigger than the path. Use +1 to move the zero byte too. */
+ memmove(&path[1], path, strlen(path)+1);
+ path[0] = '/';
+ rebuild_url = TRUE;
+ }
+ else {
+ /* sanitise paths and remove ../ and ./ sequences according to RFC3986 */
+ char *newp = Curl_dedotdotify(path);
+ if(!newp)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(strcmp(newp, path)) {
+ rebuild_url = TRUE;
+ free(data->state.pathbuffer);
+ data->state.pathbuffer = newp;
+ data->state.path = newp;
+ path = newp;
+ }
+ else
+ free(newp);
+ }
+
+ /*
+ * "rebuild_url" means that one or more URL components have been modified so
+ * we need to generate an updated full version. We need the corrected URL
+ * when communicating over HTTP proxy and we don't know at this point if
+ * we're using a proxy or not.
+ */
+ if(rebuild_url) {
+ char *reurl;
+
+ size_t plen = strlen(path); /* new path, should be 1 byte longer than
+ the original */
+ size_t urllen = strlen(data->change.url); /* original URL length */
+
+ size_t prefixlen = strlen(conn->host.name);
+
+ if(!*prot_missing)
+ prefixlen += strlen(protop) + strlen("://");
+
+ reurl = malloc(urllen + 2); /* 2 for zerobyte + slash */
+ if(!reurl)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* copy the prefix */
+ memcpy(reurl, data->change.url, prefixlen);
+
+ /* append the trailing piece + zerobyte */
+ memcpy(&reurl[prefixlen], path, plen + 1);
+
+ /* possible free the old one */
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ infof(data, "Rebuilt URL to: %s\n", reurl);
+
+ data->change.url = reurl;
+ data->change.url_alloc = TRUE; /* free this later */
+ }
+
+ /*
+ * Parse the login details from the URL and strip them out of
+ * the host name
+ */
+ result = parse_url_login(data, conn, userp, passwdp, optionsp);
+ if(result != CURLE_OK)
+ return result;
+
+ if(conn->host.name[0] == '[') {
+ /* This looks like an IPv6 address literal. See if there is an address
+ scope. */
+ char *percent = strstr (conn->host.name, "%25");
+ if(percent) {
+ char *endp;
+ unsigned long scope = strtoul (percent + 3, &endp, 10);
+ if(*endp == ']') {
+ /* The address scope was well formed. Knock it out of the
+ hostname. */
+ memmove(percent, endp, strlen(endp)+1);
+ if(!data->state.this_is_a_follow)
+ /* Don't honour a scope given in a Location: header */
+ conn->scope = (unsigned int)scope;
+ }
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ }
+ }
+
+ if(data->set.scope)
+ /* Override any scope that was set above. */
+ conn->scope = data->set.scope;
+
+ /* Remove the fragment part of the path. Per RFC 2396, this is always the
+ last part of the URI. We are looking for the first '#' so that we deal
+ gracefully with non conformant URI such as http://example.com#foo#bar. */
+ fragment = strchr(path, '#');
+ if(fragment) {
+ *fragment = 0;
+
+ /* we know the path part ended with a fragment, so we know the full URL
+ string does too and we need to cut it off from there so it isn't used
+ over proxy */
+ fragment = strchr(data->change.url, '#');
+ if(fragment)
+ *fragment = 0;
+ }
+
+ /*
+ * So if the URL was A://B/C#D,
+ * protop is A
+ * conn->host.name is B
+ * data->state.path is /C
+ */
+
+ return findprotocol(data, conn, protop);
+}
+
+/*
+ * If we're doing a resumed transfer, we need to setup our stuff
+ * properly.
+ */
+static CURLcode setup_range(struct SessionHandle *data)
+{
+ struct UrlState *s = &data->state;
+ s->resume_from = data->set.set_resume_from;
+ if(s->resume_from || data->set.str[STRING_SET_RANGE]) {
+ if(s->rangestringalloc)
+ free(s->range);
+
+ if(s->resume_from)
+ s->range = aprintf("%" FORMAT_OFF_TU "-", s->resume_from);
+ else
+ s->range = strdup(data->set.str[STRING_SET_RANGE]);
+
+ s->rangestringalloc = (s->range)?TRUE:FALSE;
+
+ if(!s->range)
+ return CURLE_OUT_OF_MEMORY;
+
+ /* tell ourselves to fetch this range */
+ s->use_range = TRUE; /* enable range download */
+ }
+ else
+ s->use_range = FALSE; /* disable range download */
+
+ return CURLE_OK;
+}
+
+
+/*
+ * setup_connection_internals() -
+ *
+ * Setup connection internals specific to the requested protocol in the
+ * SessionHandle. This is inited and setup before the connection is made but
+ * is about the particular protocol that is to be used.
+ *
+ * This MUST get called after proxy magic has been figured out.
+ */
+static CURLcode setup_connection_internals(struct connectdata *conn)
+{
+ const struct Curl_handler * p;
+ CURLcode result;
+
+ /* in some case in the multi state-machine, we go back to the CONNECT state
+ and then a second (or third or...) call to this function will be made
+ without doing a DISCONNECT or DONE in between (since the connection is
+ yet in place) and therefore this function needs to first make sure
+ there's no lingering previous data allocated. */
+ Curl_free_request_state(conn->data);
+
+ memset(&conn->data->req, 0, sizeof(struct SingleRequest));
+ conn->data->req.maxdownload = -1;
+
+ conn->socktype = SOCK_STREAM; /* most of them are TCP streams */
+
+ /* Perform setup complement if some. */
+ p = conn->handler;
+
+ if(p->setup_connection) {
+ result = (*p->setup_connection)(conn);
+
+ if(result != CURLE_OK)
+ return result;
+
+ p = conn->handler; /* May have changed. */
+ }
+
+ if(conn->port < 0)
+ /* we check for -1 here since if proxy was detected already, this
+ was very likely already set to the proxy port */
+ conn->port = p->defport;
+
+ /* only if remote_port was not already parsed off the URL we use the
+ default port number */
+ if(!conn->remote_port)
+ conn->remote_port = (unsigned short)conn->given->defport;
+
+ return CURLE_OK;
+}
+
+/*
+ * Curl_free_request_state() should free temp data that was allocated in the
+ * SessionHandle for this single request.
+ */
+
+void Curl_free_request_state(struct SessionHandle *data)
+{
+ Curl_safefree(data->req.protop);
+}
+
+
+#ifndef CURL_DISABLE_PROXY
+/****************************************************************
+* Checks if the host is in the noproxy list. returns true if it matches
+* and therefore the proxy should NOT be used.
+****************************************************************/
+static bool check_noproxy(const char* name, const char* no_proxy)
+{
+ /* no_proxy=domain1.dom,host.domain2.dom
+ * (a comma-separated list of hosts which should
+ * not be proxied, or an asterisk to override
+ * all proxy variables)
+ */
+ size_t tok_start;
+ size_t tok_end;
+ const char* separator = ", ";
+ size_t no_proxy_len;
+ size_t namelen;
+ char *endptr;
+
+ if(no_proxy && no_proxy[0]) {
+ if(Curl_raw_equal("*", no_proxy)) {
+ return TRUE;
+ }
+
+ /* NO_PROXY was specified and it wasn't just an asterisk */
+
+ no_proxy_len = strlen(no_proxy);
+ endptr = strchr(name, ':');
+ if(endptr)
+ namelen = endptr - name;
+ else
+ namelen = strlen(name);
+
+ for(tok_start = 0; tok_start < no_proxy_len; tok_start = tok_end + 1) {
+ while(tok_start < no_proxy_len &&
+ strchr(separator, no_proxy[tok_start]) != NULL) {
+ /* Look for the beginning of the token. */
+ ++tok_start;
+ }
+
+ if(tok_start == no_proxy_len)
+ break; /* It was all trailing separator chars, no more tokens. */
+
+ for(tok_end = tok_start; tok_end < no_proxy_len &&
+ strchr(separator, no_proxy[tok_end]) == NULL; ++tok_end)
+ /* Look for the end of the token. */
+ ;
+
+ /* To match previous behaviour, where it was necessary to specify
+ * ".local.com" to prevent matching "notlocal.com", we will leave
+ * the '.' off.
+ */
+ if(no_proxy[tok_start] == '.')
+ ++tok_start;
+
+ if((tok_end - tok_start) <= namelen) {
+ /* Match the last part of the name to the domain we are checking. */
+ const char *checkn = name + namelen - (tok_end - tok_start);
+ if(Curl_raw_nequal(no_proxy + tok_start, checkn,
+ tok_end - tok_start)) {
+ if((tok_end - tok_start) == namelen || *(checkn - 1) == '.') {
+ /* We either have an exact match, or the previous character is a .
+ * so it is within the same domain, so no proxy for this host.
+ */
+ return TRUE;
+ }
+ }
+ } /* if((tok_end - tok_start) <= namelen) */
+ } /* for(tok_start = 0; tok_start < no_proxy_len;
+ tok_start = tok_end + 1) */
+ } /* NO_PROXY was specified and it wasn't just an asterisk */
+
+ return FALSE;
+}
+
+/****************************************************************
+* Detect what (if any) proxy to use. Remember that this selects a host
+* name and is not limited to HTTP proxies only.
+* The returned pointer must be freed by the caller (unless NULL)
+****************************************************************/
+static char *detect_proxy(struct connectdata *conn)
+{
+ char *proxy = NULL;
+
+#ifndef CURL_DISABLE_HTTP
+ /* If proxy was not specified, we check for default proxy environment
+ * variables, to enable i.e Lynx compliance:
+ *
+ * http_proxy=http://some.server.dom:port/
+ * https_proxy=http://some.server.dom:port/
+ * ftp_proxy=http://some.server.dom:port/
+ * no_proxy=domain1.dom,host.domain2.dom
+ * (a comma-separated list of hosts which should
+ * not be proxied, or an asterisk to override
+ * all proxy variables)
+ * all_proxy=http://some.server.dom:port/
+ * (seems to exist for the CERN www lib. Probably
+ * the first to check for.)
+ *
+ * For compatibility, the all-uppercase versions of these variables are
+ * checked if the lowercase versions don't exist.
+ */
+ char *no_proxy=NULL;
+ char proxy_env[128];
+
+ no_proxy=curl_getenv("no_proxy");
+ if(!no_proxy)
+ no_proxy=curl_getenv("NO_PROXY");
+
+ if(!check_noproxy(conn->host.name, no_proxy)) {
+ /* It was not listed as without proxy */
+ const char *protop = conn->handler->scheme;
+ char *envp = proxy_env;
+ char *prox;
+
+ /* Now, build <protocol>_proxy and check for such a one to use */
+ while(*protop)
+ *envp++ = (char)tolower((int)*protop++);
+
+ /* append _proxy */
+ strcpy(envp, "_proxy");
+
+ /* read the protocol proxy: */
+ prox=curl_getenv(proxy_env);
+
+ /*
+ * We don't try the uppercase version of HTTP_PROXY because of
+ * security reasons:
+ *
+ * When curl is used in a webserver application
+ * environment (cgi or php), this environment variable can
+ * be controlled by the web server user by setting the
+ * http header 'Proxy:' to some value.
+ *
+ * This can cause 'internal' http/ftp requests to be
+ * arbitrarily redirected by any external attacker.
+ */
+ if(!prox && !Curl_raw_equal("http_proxy", proxy_env)) {
+ /* There was no lowercase variable, try the uppercase version: */
+ Curl_strntoupper(proxy_env, proxy_env, sizeof(proxy_env));
+ prox=curl_getenv(proxy_env);
+ }
+
+ if(prox && *prox) { /* don't count "" strings */
+ proxy = prox; /* use this */
+ }
+ else {
+ proxy = curl_getenv("all_proxy"); /* default proxy to use */
+ if(!proxy)
+ proxy=curl_getenv("ALL_PROXY");
+ }
+ } /* if(!check_noproxy(conn->host.name, no_proxy)) - it wasn't specified
+ non-proxy */
+ if(no_proxy)
+ free(no_proxy);
+
+#else /* !CURL_DISABLE_HTTP */
+
+ (void)conn;
+#endif /* CURL_DISABLE_HTTP */
+
+ return proxy;
+}
+
+/*
+ * If this is supposed to use a proxy, we need to figure out the proxy
+ * host name, so that we can re-use an existing connection
+ * that may exist registered to the same proxy host.
+ * proxy will be freed before this function returns.
+ */
+static CURLcode parse_proxy(struct SessionHandle *data,
+ struct connectdata *conn, char *proxy)
+{
+ char *prox_portno;
+ char *endofprot;
+
+ /* We use 'proxyptr' to point to the proxy name from now on... */
+ char *proxyptr;
+ char *portptr;
+ char *atsign;
+
+ /* We do the proxy host string parsing here. We want the host name and the
+ * port name. Accept a protocol:// prefix
+ */
+
+ /* Parse the protocol part if present */
+ endofprot = strstr(proxy, "://");
+ if(endofprot) {
+ proxyptr = endofprot+3;
+ if(checkprefix("socks5h", proxy))
+ conn->proxytype = CURLPROXY_SOCKS5_HOSTNAME;
+ else if(checkprefix("socks5", proxy))
+ conn->proxytype = CURLPROXY_SOCKS5;
+ else if(checkprefix("socks4a", proxy))
+ conn->proxytype = CURLPROXY_SOCKS4A;
+ else if(checkprefix("socks4", proxy) || checkprefix("socks", proxy))
+ conn->proxytype = CURLPROXY_SOCKS4;
+ /* Any other xxx:// : change to http proxy */
+ }
+ else
+ proxyptr = proxy; /* No xxx:// head: It's a HTTP proxy */
+
+ /* Is there a username and password given in this proxy url? */
+ atsign = strchr(proxyptr, '@');
+ if(atsign) {
+ CURLcode res = CURLE_OK;
+ char *proxyuser = NULL;
+ char *proxypasswd = NULL;
+
+ res = parse_login_details(proxyptr, atsign - proxyptr,
+ &proxyuser, &proxypasswd, NULL);
+ if(!res) {
+ /* found user and password, rip them out. note that we are
+ unescaping them, as there is otherwise no way to have a
+ username or password with reserved characters like ':' in
+ them. */
+ Curl_safefree(conn->proxyuser);
+ if(proxyuser && strlen(proxyuser) < MAX_CURL_USER_LENGTH)
+ conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+ else
+ conn->proxyuser = strdup("");
+
+ if(!conn->proxyuser)
+ res = CURLE_OUT_OF_MEMORY;
+ else {
+ Curl_safefree(conn->proxypasswd);
+ if(proxypasswd && strlen(proxypasswd) < MAX_CURL_PASSWORD_LENGTH)
+ conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+ else
+ conn->proxypasswd = strdup("");
+
+ if(!conn->proxypasswd)
+ res = CURLE_OUT_OF_MEMORY;
+ }
+
+ if(!res) {
+ conn->bits.proxy_user_passwd = TRUE; /* enable it */
+ atsign++; /* the right side of the @-letter */
+
+ if(atsign)
+ proxyptr = atsign; /* now use this instead */
+ else
+ res = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ Curl_safefree(proxyuser);
+ Curl_safefree(proxypasswd);
+
+ if(res)
+ return res;
+ }
+
+ /* start scanning for port number at this point */
+ portptr = proxyptr;
+
+ /* detect and extract RFC2732-style IPv6-addresses */
+ if(*proxyptr == '[') {
+ char *ptr = ++proxyptr; /* advance beyond the initial bracket */
+ while(*ptr && (ISXDIGIT(*ptr) || (*ptr == ':') || (*ptr == '%') ||
+ (*ptr == '.')))
+ ptr++;
+ if(*ptr == ']')
+ /* yeps, it ended nicely with a bracket as well */
+ *ptr++ = 0;
+ else
+ infof(data, "Invalid IPv6 address format\n");
+ portptr = ptr;
+ /* Note that if this didn't end with a bracket, we still advanced the
+ * proxyptr first, but I can't see anything wrong with that as no host
+ * name nor a numeric can legally start with a bracket.
+ */
+ }
+
+ /* Get port number off proxy.server.com:1080 */
+ prox_portno = strchr(portptr, ':');
+ if(prox_portno) {
+ *prox_portno = 0x0; /* cut off number from host name */
+ prox_portno ++;
+ /* now set the local port number */
+ conn->port = strtol(prox_portno, NULL, 10);
+ }
+ else {
+ if(proxyptr[0]=='/')
+ /* If the first character in the proxy string is a slash, fail
+ immediately. The following code will otherwise clear the string which
+ will lead to code running as if no proxy was set! */
+ return CURLE_COULDNT_RESOLVE_PROXY;
+
+ /* without a port number after the host name, some people seem to use
+ a slash so we strip everything from the first slash */
+ atsign = strchr(proxyptr, '/');
+ if(atsign)
+ *atsign = 0x0; /* cut off path part from host name */
+
+ if(data->set.proxyport)
+ /* None given in the proxy string, then get the default one if it is
+ given */
+ conn->port = data->set.proxyport;
+ }
+
+ /* now, clone the cleaned proxy host name */
+ conn->proxy.rawalloc = strdup(proxyptr);
+ conn->proxy.name = conn->proxy.rawalloc;
+
+ if(!conn->proxy.rawalloc)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+
+/*
+ * Extract the user and password from the authentication string
+ */
+static CURLcode parse_proxy_auth(struct SessionHandle *data,
+ struct connectdata *conn)
+{
+ char proxyuser[MAX_CURL_USER_LENGTH]="";
+ char proxypasswd[MAX_CURL_PASSWORD_LENGTH]="";
+
+ if(data->set.str[STRING_PROXYUSERNAME] != NULL) {
+ strncpy(proxyuser, data->set.str[STRING_PROXYUSERNAME],
+ MAX_CURL_USER_LENGTH);
+ proxyuser[MAX_CURL_USER_LENGTH-1] = '\0'; /*To be on safe side*/
+ }
+ if(data->set.str[STRING_PROXYPASSWORD] != NULL) {
+ strncpy(proxypasswd, data->set.str[STRING_PROXYPASSWORD],
+ MAX_CURL_PASSWORD_LENGTH);
+ proxypasswd[MAX_CURL_PASSWORD_LENGTH-1] = '\0'; /*To be on safe side*/
+ }
+
+ conn->proxyuser = curl_easy_unescape(data, proxyuser, 0, NULL);
+ if(!conn->proxyuser)
+ return CURLE_OUT_OF_MEMORY;
+
+ conn->proxypasswd = curl_easy_unescape(data, proxypasswd, 0, NULL);
+ if(!conn->proxypasswd)
+ return CURLE_OUT_OF_MEMORY;
+
+ return CURLE_OK;
+}
+#endif /* CURL_DISABLE_PROXY */
+
+/*
+ * parse_url_login()
+ *
+ * Parse the login details (user name, password and options) from the URL and
+ * strip them out of the host name
+ *
+ * Inputs: data->set.use_netrc (CURLOPT_NETRC)
+ * conn->host.name
+ *
+ * Outputs: (almost :- all currently undefined)
+ * conn->bits.user_passwd - non-zero if non-default passwords exist
+ * user - non-zero length if defined
+ * passwd - non-zero length if defined
+ * options - non-zero length if defined
+ * conn->host.name - remove user name and password
+ */
+static CURLcode parse_url_login(struct SessionHandle *data,
+ struct connectdata *conn,
+ char **user, char **passwd, char **options)
+{
+ CURLcode result = CURLE_OK;
+ char *userp = NULL;
+ char *passwdp = NULL;
+ char *optionsp = NULL;
+
+ /* At this point, we're hoping all the other special cases have
+ * been taken care of, so conn->host.name is at most
+ * [user[:password][;options]]@]hostname
+ *
+ * We need somewhere to put the embedded details, so do that first.
+ */
+
+ char *ptr = strchr(conn->host.name, '@');
+ char *login = conn->host.name;
+
+ DEBUGASSERT(!**user);
+ DEBUGASSERT(!**passwd);
+ DEBUGASSERT(!**options);
+
+ if(!ptr)
+ goto out;
+
+ /* We will now try to extract the
+ * possible login information in a string like:
+ * ftp://user:password@ftp.my.site:8021/README */
+ conn->host.name = ++ptr;
+
+ /* So the hostname is sane. Only bother interpreting the
+ * results if we could care. It could still be wasted
+ * work because it might be overtaken by the programmatically
+ * set user/passwd, but doing that first adds more cases here :-(
+ */
+
+ if(data->set.use_netrc == CURL_NETRC_REQUIRED)
+ goto out;
+
+ /* We could use the login information in the URL so extract it */
+ result = parse_login_details(login, ptr - login - 1,
+ &userp, &passwdp, &optionsp);
+ if(result != CURLE_OK)
+ goto out;
+
+ if(userp) {
+ char *newname;
+
+ /* We have a user in the URL */
+ conn->bits.userpwd_in_url = TRUE;
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+
+ /* Decode the user */
+ newname = curl_easy_unescape(data, userp, 0, NULL);
+ if(!newname) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ free(*user);
+ *user = newname;
+ }
+
+ if(passwdp) {
+ /* We have a password in the URL so decode it */
+ char *newpasswd = curl_easy_unescape(data, passwdp, 0, NULL);
+ if(!newpasswd) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ free(*passwd);
+ *passwd = newpasswd;
+ }
+
+ if(optionsp) {
+ /* We have an options list in the URL so decode it */
+ char *newoptions = curl_easy_unescape(data, optionsp, 0, NULL);
+ if(!newoptions) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ free(*options);
+ *options = newoptions;
+ }
+
+
+ out:
+
+ Curl_safefree(userp);
+ Curl_safefree(passwdp);
+ Curl_safefree(optionsp);
+
+ return result;
+}
+
+/*
+ * parse_login_details()
+ *
+ * This is used to parse a login string for user name, password and options in
+ * the following formats:
+ *
+ * user
+ * user:password
+ * user:password;options
+ * user;options
+ * user;options:password
+ * :password
+ * :password;options
+ * ;options
+ * ;options:password
+ *
+ * Parameters:
+ *
+ * login [in] - The login string.
+ * len [in] - The length of the login string.
+ * userp [in/out] - The address where a pointer to newly allocated memory
+ * holding the user will be stored upon completion.
+ * passdwp [in/out] - The address where a pointer to newly allocated memory
+ * holding the password will be stored upon completion.
+ * optionsp [in/out] - The address where a pointer to newly allocated memory
+ * holding the options will be stored upon completion.
+ *
+ * Returns CURLE_OK on success.
+ */
+static CURLcode parse_login_details(const char *login, const size_t len,
+ char **userp, char **passwdp,
+ char **optionsp)
+{
+ CURLcode result = CURLE_OK;
+ char *ubuf = NULL;
+ char *pbuf = NULL;
+ char *obuf = NULL;
+ const char *psep = NULL;
+ const char *osep = NULL;
+ size_t ulen;
+ size_t plen;
+ size_t olen;
+
+ /* Attempt to find the password separator */
+ if(passwdp) {
+ psep = strchr(login, ':');
+
+ /* Within the constraint of the login string */
+ if(psep >= login + len)
+ psep = NULL;
+ }
+
+ /* Attempt to find the options separator */
+ if(optionsp) {
+ osep = strchr(login, ';');
+
+ /* Within the constraint of the login string */
+ if(osep >= login + len)
+ osep = NULL;
+ }
+
+ /* Calculate the portion lengths */
+ ulen = (psep ?
+ (size_t)(osep && psep > osep ? osep - login : psep - login) :
+ (osep ? (size_t)(osep - login) : len));
+ plen = (psep ?
+ (osep && osep > psep ? (size_t)(osep - psep) :
+ (size_t)(login + len - psep)) - 1 : 0);
+ olen = (osep ?
+ (psep && psep > osep ? (size_t)(psep - osep) :
+ (size_t)(login + len - osep)) - 1 : 0);
+
+ /* Allocate the user portion buffer */
+ if(userp && ulen) {
+ ubuf = malloc(ulen + 1);
+ if(!ubuf)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ /* Allocate the password portion buffer */
+ if(!result && passwdp && plen) {
+ pbuf = malloc(plen + 1);
+ if(!pbuf) {
+ Curl_safefree(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ /* Allocate the options portion buffer */
+ if(!result && optionsp && olen) {
+ obuf = malloc(olen + 1);
+ if(!obuf) {
+ Curl_safefree(pbuf);
+ Curl_safefree(ubuf);
+ result = CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+ if(!result) {
+ /* Store the user portion if necessary */
+ if(ubuf) {
+ memcpy(ubuf, login, ulen);
+ ubuf[ulen] = '\0';
+ Curl_safefree(*userp);
+ *userp = ubuf;
+ }
+
+ /* Store the password portion if necessary */
+ if(pbuf) {
+ memcpy(pbuf, psep + 1, plen);
+ pbuf[plen] = '\0';
+ Curl_safefree(*passwdp);
+ *passwdp = pbuf;
+ }
+
+ /* Store the options portion if necessary */
+ if(obuf) {
+ memcpy(obuf, osep + 1, olen);
+ obuf[olen] = '\0';
+ Curl_safefree(*optionsp);
+ *optionsp = obuf;
+ }
+ }
+
+ return result;
+}
+
+/*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *
+ * No matter if we use a proxy or not, we have to figure out the remote
+ * port number of various reasons.
+ *
+ * To be able to detect port number flawlessly, we must not confuse them
+ * IPv6-specified addresses in the [0::1] style. (RFC2732)
+ *
+ * The conn->host.name is currently [user:passwd@]host[:port] where host
+ * could be a hostname, IPv4 address or IPv6 address.
+ *
+ * The port number embedded in the URL is replaced, if necessary.
+ *************************************************************/
+static CURLcode parse_remote_port(struct SessionHandle *data,
+ struct connectdata *conn)
+{
+ char *portptr;
+ char endbracket;
+
+ /* Note that at this point, the IPv6 address cannot contain any scope
+ suffix as that has already been removed in the parseurlandfillconn()
+ function */
+ if((1 == sscanf(conn->host.name, "[%*45[0123456789abcdefABCDEF:.]%c",
+ &endbracket)) &&
+ (']' == endbracket)) {
+ /* this is a RFC2732-style specified IP-address */
+ conn->bits.ipv6_ip = TRUE;
+
+ conn->host.name++; /* skip over the starting bracket */
+ portptr = strchr(conn->host.name, ']');
+ if(portptr) {
+ *portptr++ = '\0'; /* zero terminate, killing the bracket */
+ if(':' != *portptr)
+ portptr = NULL; /* no port number available */
+ }
+ }
+ else {
+#ifdef ENABLE_IPV6
+ struct in6_addr in6;
+ if(Curl_inet_pton(AF_INET6, conn->host.name, &in6) > 0) {
+ /* This is a numerical IPv6 address, meaning this is a wrongly formatted
+ URL */
+ failf(data, "IPv6 numerical address used in URL without brackets");
+ return CURLE_URL_MALFORMAT;
+ }
+#endif
+
+ portptr = strrchr(conn->host.name, ':');
+ }
+
+ if(data->set.use_port && data->state.allow_port) {
+ /* if set, we use this and ignore the port possibly given in the URL */
+ conn->remote_port = (unsigned short)data->set.use_port;
+ if(portptr)
+ *portptr = '\0'; /* cut off the name there anyway - if there was a port
+ number - since the port number is to be ignored! */
+ if(conn->bits.httpproxy) {
+ /* we need to create new URL with the new port number */
+ char *url;
+ char type[12]="";
+
+ if(conn->bits.type_set)
+ snprintf(type, sizeof(type), ";type=%c",
+ data->set.prefer_ascii?'A':
+ (data->set.ftp_list_only?'D':'I'));
+
+ /*
+ * This synthesized URL isn't always right--suffixes like ;type=A are
+ * stripped off. It would be better to work directly from the original
+ * URL and simply replace the port part of it.
+ */
+ url = aprintf("%s://%s%s%s:%hu%s%s%s", conn->given->scheme,
+ conn->bits.ipv6_ip?"[":"", conn->host.name,
+ conn->bits.ipv6_ip?"]":"", conn->remote_port,
+ data->state.slash_removed?"/":"", data->state.path,
+ type);
+ if(!url)
+ return CURLE_OUT_OF_MEMORY;
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = url;
+ data->change.url_alloc = TRUE;
+ }
+ }
+ else if(portptr) {
+ /* no CURLOPT_PORT given, extract the one from the URL */
+
+ char *rest;
+ unsigned long port;
+
+ port=strtoul(portptr+1, &rest, 10); /* Port number must be decimal */
+
+ if(rest != (portptr+1) && *rest == '\0') {
+ /* The colon really did have only digits after it,
+ * so it is either a port number or a mistake */
+
+ if(port > 0xffff) { /* Single unix standard says port numbers are
+ * 16 bits long */
+ failf(data, "Port number too large: %lu", port);
+ return CURLE_URL_MALFORMAT;
+ }
+
+ *portptr = '\0'; /* cut off the name there */
+ conn->remote_port = curlx_ultous(port);
+ }
+ else if(!port)
+ /* Browser behavior adaptation. If there's a colon with no digits after,
+ just cut off the name there which makes us ignore the colon and just
+ use the default port. Firefox and Chrome both do that. */
+ *portptr = '\0';
+ }
+ return CURLE_OK;
+}
+
+/*
+ * Override the login details from the URL with that in the CURLOPT_USERPWD
+ * option or a .netrc file, if applicable.
+ */
+static CURLcode override_login(struct SessionHandle *data,
+ struct connectdata *conn,
+ char **userp, char **passwdp, char **optionsp)
+{
+ if(data->set.str[STRING_USERNAME]) {
+ free(*userp);
+ *userp = strdup(data->set.str[STRING_USERNAME]);
+ if(!*userp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->set.str[STRING_PASSWORD]) {
+ free(*passwdp);
+ *passwdp = strdup(data->set.str[STRING_PASSWORD]);
+ if(!*passwdp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ if(data->set.str[STRING_OPTIONS]) {
+ free(*optionsp);
+ *optionsp = strdup(data->set.str[STRING_OPTIONS]);
+ if(!*optionsp)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ conn->bits.netrc = FALSE;
+ if(data->set.use_netrc != CURL_NETRC_IGNORED) {
+ if(Curl_parsenetrc(conn->host.name,
+ userp, passwdp,
+ data->set.str[STRING_NETRC_FILE])) {
+ infof(data, "Couldn't find host %s in the "
+ DOT_CHAR "netrc file; using defaults\n",
+ conn->host.name);
+ }
+ else {
+ /* set bits.netrc TRUE to remember that we got the name from a .netrc
+ file, so that it is safe to use even if we followed a Location: to a
+ different host or similar. */
+ conn->bits.netrc = TRUE;
+
+ conn->bits.user_passwd = TRUE; /* enable user+password */
+ }
+ }
+
+ return CURLE_OK;
+}
+
+/*
+ * Set password so it's available in the connection.
+ */
+static CURLcode set_login(struct connectdata *conn,
+ const char *user, const char *passwd,
+ const char *options)
+{
+ CURLcode result = CURLE_OK;
+
+ /* If our protocol needs a password and we have none, use the defaults */
+ if((conn->handler->flags & PROTOPT_NEEDSPWD) && !conn->bits.user_passwd) {
+ /* Store the default user */
+ conn->user = strdup(CURL_DEFAULT_USER);
+
+ /* Store the default password */
+ if(conn->user)
+ conn->passwd = strdup(CURL_DEFAULT_PASSWORD);
+ else
+ conn->passwd = NULL;
+
+ /* This is the default password, so DON'T set conn->bits.user_passwd */
+ }
+ else {
+ /* Store the user, zero-length if not set */
+ conn->user = strdup(user);
+
+ /* Store the password (only if user is present), zero-length if not set */
+ if(conn->user)
+ conn->passwd = strdup(passwd);
+ else
+ conn->passwd = NULL;
+ }
+
+ if(!conn->user || !conn->passwd)
+ result = CURLE_OUT_OF_MEMORY;
+
+ /* Store the options, null if not set */
+ if(!result && options[0]) {
+ conn->options = strdup(options);
+
+ if(!conn->options)
+ result = CURLE_OUT_OF_MEMORY;
+ }
+
+ return result;
+}
+
+/*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+static CURLcode resolve_server(struct SessionHandle *data,
+ struct connectdata *conn,
+ bool *async)
+{
+ CURLcode result=CURLE_OK;
+ long timeout_ms = Curl_timeleft(data, NULL, TRUE);
+
+ /*************************************************************
+ * Resolve the name of the server or proxy
+ *************************************************************/
+ if(conn->bits.reuse)
+ /* We're reusing the connection - no need to resolve anything, and
+ fix_hostname() was called already in create_conn() for the re-use
+ case. */
+ *async = FALSE;
+
+ else {
+ /* this is a fresh connect */
+ int rc;
+ struct Curl_dns_entry *hostaddr;
+
+ /* set a pointer to the hostname we display */
+ fix_hostname(data, conn, &conn->host);
+
+ if(!conn->proxy.name || !*conn->proxy.name) {
+ /* If not connecting via a proxy, extract the port from the URL, if it is
+ * there, thus overriding any defaults that might have been set above. */
+ conn->port = conn->remote_port; /* it is the same port */
+
+ /* Resolve target host right on */
+ rc = Curl_resolv_timeout(conn, conn->host.name, (int)conn->port,
+ &hostaddr, timeout_ms);
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(rc == CURLRESOLV_TIMEDOUT)
+ result = CURLE_OPERATION_TIMEDOUT;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve host '%s'", conn->host.dispname);
+ result = CURLE_COULDNT_RESOLVE_HOST;
+ /* don't return yet, we need to clean up the timeout first */
+ }
+ }
+ else {
+ /* This is a proxy that hasn't been resolved yet. */
+
+ /* IDN-fix the proxy name */
+ fix_hostname(data, conn, &conn->proxy);
+
+ /* resolve proxy */
+ rc = Curl_resolv_timeout(conn, conn->proxy.name, (int)conn->port,
+ &hostaddr, timeout_ms);
+
+ if(rc == CURLRESOLV_PENDING)
+ *async = TRUE;
+
+ else if(rc == CURLRESOLV_TIMEDOUT)
+ result = CURLE_OPERATION_TIMEDOUT;
+
+ else if(!hostaddr) {
+ failf(data, "Couldn't resolve proxy '%s'", conn->proxy.dispname);
+ result = CURLE_COULDNT_RESOLVE_PROXY;
+ /* don't return yet, we need to clean up the timeout first */
+ }
+ }
+ DEBUGASSERT(conn->dns_entry == NULL);
+ conn->dns_entry = hostaddr;
+ }
+
+ return result;
+}
+
+/*
+ * Cleanup the connection just allocated before we can move along and use the
+ * previously existing one. All relevant data is copied over and old_conn is
+ * ready for freeing once this function returns.
+ */
+static void reuse_conn(struct connectdata *old_conn,
+ struct connectdata *conn)
+{
+ if(old_conn->proxy.rawalloc)
+ free(old_conn->proxy.rawalloc);
+
+ /* free the SSL config struct from this connection struct as this was
+ allocated in vain and is targeted for destruction */
+ Curl_free_ssl_config(&old_conn->ssl_config);
+
+ conn->data = old_conn->data;
+
+ /* get the user+password information from the old_conn struct since it may
+ * be new for this request even when we re-use an existing connection */
+ conn->bits.user_passwd = old_conn->bits.user_passwd;
+ if(conn->bits.user_passwd) {
+ /* use the new user name and password though */
+ Curl_safefree(conn->user);
+ Curl_safefree(conn->passwd);
+ conn->user = old_conn->user;
+ conn->passwd = old_conn->passwd;
+ old_conn->user = NULL;
+ old_conn->passwd = NULL;
+ }
+
+ conn->bits.proxy_user_passwd = old_conn->bits.proxy_user_passwd;
+ if(conn->bits.proxy_user_passwd) {
+ /* use the new proxy user name and proxy password though */
+ Curl_safefree(conn->proxyuser);
+ Curl_safefree(conn->proxypasswd);
+ conn->proxyuser = old_conn->proxyuser;
+ conn->proxypasswd = old_conn->proxypasswd;
+ old_conn->proxyuser = NULL;
+ old_conn->proxypasswd = NULL;
+ }
+
+ /* host can change, when doing keepalive with a proxy or if the case is
+ different this time etc */
+ Curl_safefree(conn->host.rawalloc);
+ conn->host=old_conn->host;
+
+ /* persist connection info in session handle */
+ Curl_persistconninfo(conn);
+
+ /* re-use init */
+ conn->bits.reuse = TRUE; /* yes, we're re-using here */
+
+ Curl_safefree(old_conn->user);
+ Curl_safefree(old_conn->passwd);
+ Curl_safefree(old_conn->proxyuser);
+ Curl_safefree(old_conn->proxypasswd);
+ Curl_safefree(old_conn->localdev);
+
+ Curl_llist_destroy(old_conn->send_pipe, NULL);
+ Curl_llist_destroy(old_conn->recv_pipe, NULL);
+
+ old_conn->send_pipe = NULL;
+ old_conn->recv_pipe = NULL;
+
+ Curl_safefree(old_conn->master_buffer);
+}
+
+/**
+ * create_conn() sets up a new connectdata struct, or re-uses an already
+ * existing one, and resolves host name.
+ *
+ * if this function returns CURLE_OK and *async is set to TRUE, the resolve
+ * response will be coming asynchronously. If *async is FALSE, the name is
+ * already resolved.
+ *
+ * @param data The sessionhandle pointer
+ * @param in_connect is set to the next connection data pointer
+ * @param async is set TRUE when an async DNS resolution is pending
+ * @see Curl_setup_conn()
+ *
+ * *NOTE* this function assigns the conn->data pointer!
+ */
+
+static CURLcode create_conn(struct SessionHandle *data,
+ struct connectdata **in_connect,
+ bool *async)
+{
+ CURLcode result = CURLE_OK;
+ struct connectdata *conn;
+ struct connectdata *conn_temp = NULL;
+ size_t urllen;
+ char *user = NULL;
+ char *passwd = NULL;
+ char *options = NULL;
+ bool reuse;
+ char *proxy = NULL;
+ bool prot_missing = FALSE;
+ bool no_connections_available = FALSE;
+ bool force_reuse;
+ size_t max_host_connections = Curl_multi_max_host_connections(data->multi);
+ size_t max_total_connections = Curl_multi_max_total_connections(data->multi);
+
+ *async = FALSE;
+
+ /*************************************************************
+ * Check input data
+ *************************************************************/
+
+ if(!data->change.url) {
+ result = CURLE_URL_MALFORMAT;
+ goto out;
+ }
+
+ /* First, split up the current URL in parts so that we can use the
+ parts for checking against the already present connections. In order
+ to not have to modify everything at once, we allocate a temporary
+ connection data struct and fill in for comparison purposes. */
+ conn = allocate_conn(data);
+
+ if(!conn) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /* We must set the return variable as soon as possible, so that our
+ parent can cleanup any possible allocs we may have done before
+ any failure */
+ *in_connect = conn;
+
+ /* This initing continues below, see the comment "Continue connectdata
+ * initialization here" */
+
+ /***********************************************************
+ * We need to allocate memory to store the path in. We get the size of the
+ * full URL to be sure, and we need to make it at least 256 bytes since
+ * other parts of the code will rely on this fact
+ ***********************************************************/
+#define LEAST_PATH_ALLOC 256
+ urllen=strlen(data->change.url);
+ if(urllen < LEAST_PATH_ALLOC)
+ urllen=LEAST_PATH_ALLOC;
+
+ /*
+ * We malloc() the buffers below urllen+2 to make room for 2 possibilities:
+ * 1 - an extra terminating zero
+ * 2 - an extra slash (in case a syntax like "www.host.com?moo" is used)
+ */
+
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+
+ data->state.pathbuffer = malloc(urllen+2);
+ if(NULL == data->state.pathbuffer) {
+ result = CURLE_OUT_OF_MEMORY; /* really bad error */
+ goto out;
+ }
+ data->state.path = data->state.pathbuffer;
+
+ conn->host.rawalloc = malloc(urllen+2);
+ if(NULL == conn->host.rawalloc) {
+ Curl_safefree(data->state.pathbuffer);
+ data->state.path = NULL;
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ conn->host.name = conn->host.rawalloc;
+ conn->host.name[0] = 0;
+
+ user = strdup("");
+ passwd = strdup("");
+ options = strdup("");
+ if(!user || !passwd || !options) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ result = parseurlandfillconn(data, conn, &prot_missing, &user, &passwd,
+ &options);
+ if(result != CURLE_OK)
+ goto out;
+
+ /*************************************************************
+ * No protocol part in URL was used, add it!
+ *************************************************************/
+ if(prot_missing) {
+ /* We're guessing prefixes here and if we're told to use a proxy or if
+ we're gonna follow a Location: later or... then we need the protocol
+ part added so that we have a valid URL. */
+ char *reurl;
+
+ reurl = aprintf("%s://%s", conn->handler->scheme, data->change.url);
+
+ if(!reurl) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ if(data->change.url_alloc) {
+ Curl_safefree(data->change.url);
+ data->change.url_alloc = FALSE;
+ }
+
+ data->change.url = reurl;
+ data->change.url_alloc = TRUE; /* free this later */
+ }
+
+ /*************************************************************
+ * If the protocol can't handle url query strings, then cut
+ * of the unhandable part
+ *************************************************************/
+ if((conn->given->flags&PROTOPT_NOURLQUERY)) {
+ char *path_q_sep = strchr(conn->data->state.path, '?');
+ if(path_q_sep) {
+ /* according to rfc3986, allow the query (?foo=bar)
+ also on protocols that can't handle it.
+
+ cut the string-part after '?'
+ */
+
+ /* terminate the string */
+ path_q_sep[0] = 0;
+ }
+ }
+
+ if(data->set.str[STRING_BEARER]) {
+ conn->xoauth2_bearer = strdup(data->set.str[STRING_BEARER]);
+ if(!conn->xoauth2_bearer) {
+ return CURLE_OUT_OF_MEMORY;
+ }
+ }
+
+#ifndef CURL_DISABLE_PROXY
+ /*************************************************************
+ * Extract the user and password from the authentication string
+ *************************************************************/
+ if(conn->bits.proxy_user_passwd) {
+ result = parse_proxy_auth(data, conn);
+ if(result != CURLE_OK)
+ goto out;
+ }
+
+ /*************************************************************
+ * Detect what (if any) proxy to use
+ *************************************************************/
+ if(data->set.str[STRING_PROXY]) {
+ proxy = strdup(data->set.str[STRING_PROXY]);
+ /* if global proxy is set, this is it */
+ if(NULL == proxy) {
+ failf(data, "memory shortage");
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+ }
+
+ if(data->set.str[STRING_NOPROXY] &&
+ check_noproxy(conn->host.name, data->set.str[STRING_NOPROXY])) {
+ if(proxy) {
+ free(proxy); /* proxy is in exception list */
+ proxy = NULL;
+ }
+ }
+ else if(!proxy)
+ proxy = detect_proxy(conn);
+
+ if(proxy && (!*proxy || (conn->handler->flags & PROTOPT_NONETWORK))) {
+ free(proxy); /* Don't bother with an empty proxy string or if the
+ protocol doesn't work with network */
+ proxy = NULL;
+ }
+
+ /***********************************************************************
+ * If this is supposed to use a proxy, we need to figure out the proxy host
+ * name, proxy type and port number, so that we can re-use an existing
+ * connection that may exist registered to the same proxy host.
+ ***********************************************************************/
+ if(proxy) {
+ result = parse_proxy(data, conn, proxy);
+
+ Curl_safefree(proxy); /* parse_proxy copies the proxy string */
+
+ if(result)
+ goto out;
+
+ if((conn->proxytype == CURLPROXY_HTTP) ||
+ (conn->proxytype == CURLPROXY_HTTP_1_0)) {
+#ifdef CURL_DISABLE_HTTP
+ /* asking for a HTTP proxy is a bit funny when HTTP is disabled... */
+ result = CURLE_UNSUPPORTED_PROTOCOL;
+ goto out;
+#else
+ /* force this connection's protocol to become HTTP if not already
+ compatible - if it isn't tunneling through */
+ if(!(conn->handler->protocol & CURLPROTO_HTTP) &&
+ !conn->bits.tunnel_proxy)
+ conn->handler = &Curl_handler_http;
+
+ conn->bits.httpproxy = TRUE;
+#endif
+ }
+ else
+ conn->bits.httpproxy = FALSE; /* not a HTTP proxy */
+ conn->bits.proxy = TRUE;
+ }
+ else {
+ /* we aren't using the proxy after all... */
+ conn->bits.proxy = FALSE;
+ conn->bits.httpproxy = FALSE;
+ conn->bits.proxy_user_passwd = FALSE;
+ conn->bits.tunnel_proxy = FALSE;
+ }
+
+#endif /* CURL_DISABLE_PROXY */
+
+ /*************************************************************
+ * If the protocol is using SSL and HTTP proxy is used, we set
+ * the tunnel_proxy bit.
+ *************************************************************/
+ if((conn->given->flags&PROTOPT_SSL) && conn->bits.httpproxy)
+ conn->bits.tunnel_proxy = TRUE;
+
+ /*************************************************************
+ * Figure out the remote port number and fix it in the URL
+ *************************************************************/
+ result = parse_remote_port(data, conn);
+ if(result != CURLE_OK)
+ goto out;
+
+ /* Check for overridden login details and set them accordingly so they
+ they are known when protocol->setup_connection is called! */
+ result = override_login(data, conn, &user, &passwd, &options);
+ if(result != CURLE_OK)
+ goto out;
+ result = set_login(conn, user, passwd, options);
+ if(result != CURLE_OK)
+ goto out;
+
+ /*************************************************************
+ * Setup internals depending on protocol. Needs to be done after
+ * we figured out what/if proxy to use.
+ *************************************************************/
+ result = setup_connection_internals(conn);
+ if(result != CURLE_OK)
+ goto out;
+
+ conn->recv[FIRSTSOCKET] = Curl_recv_plain;
+ conn->send[FIRSTSOCKET] = Curl_send_plain;
+ conn->recv[SECONDARYSOCKET] = Curl_recv_plain;
+ conn->send[SECONDARYSOCKET] = Curl_send_plain;
+
+ /***********************************************************************
+ * file: is a special case in that it doesn't need a network connection
+ ***********************************************************************/
+#ifndef CURL_DISABLE_FILE
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ bool done;
+ /* this is supposed to be the connect function so we better at least check
+ that the file is present here! */
+ DEBUGASSERT(conn->handler->connect_it);
+ result = conn->handler->connect_it(conn, &done);
+
+ /* Setup a "faked" transfer that'll do nothing */
+ if(CURLE_OK == result) {
+ conn->data = data;
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE; /* we are "connected */
+
+ ConnectionStore(data, conn);
+
+ /*
+ * Setup whatever necessary for a resumed transfer
+ */
+ result = setup_range(data);
+ if(result) {
+ DEBUGASSERT(conn->handler->done);
+ /* we ignore the return code for the protocol-specific DONE */
+ (void)conn->handler->done(conn, result, FALSE);
+ goto out;
+ }
+
+ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, /* no download */
+ -1, NULL); /* no upload */
+ }
+
+ /* since we skip do_init() */
+ do_init(conn);
+
+ goto out;
+ }
+#endif
+
+ /* Get a cloned copy of the SSL config situation stored in the
+ connection struct. But to get this going nicely, we must first make
+ sure that the strings in the master copy are pointing to the correct
+ strings in the session handle strings array!
+
+ Keep in mind that the pointers in the master copy are pointing to strings
+ that will be freed as part of the SessionHandle struct, but all cloned
+ copies will be separately allocated.
+ */
+ data->set.ssl.CApath = data->set.str[STRING_SSL_CAPATH];
+ data->set.ssl.CAfile = data->set.str[STRING_SSL_CAFILE];
+ data->set.ssl.CRLfile = data->set.str[STRING_SSL_CRLFILE];
+ data->set.ssl.issuercert = data->set.str[STRING_SSL_ISSUERCERT];
+ data->set.ssl.random_file = data->set.str[STRING_SSL_RANDOM_FILE];
+ data->set.ssl.egdsocket = data->set.str[STRING_SSL_EGDSOCKET];
+ data->set.ssl.cipher_list = data->set.str[STRING_SSL_CIPHER_LIST];
+#ifdef USE_TLS_SRP
+ data->set.ssl.username = data->set.str[STRING_TLSAUTH_USERNAME];
+ data->set.ssl.password = data->set.str[STRING_TLSAUTH_PASSWORD];
+#endif
+
+ if(!Curl_clone_ssl_config(&data->set.ssl, &conn->ssl_config)) {
+ result = CURLE_OUT_OF_MEMORY;
+ goto out;
+ }
+
+ /*************************************************************
+ * Check the current list of connections to see if we can
+ * re-use an already existing one or if we have to create a
+ * new one.
+ *************************************************************/
+
+ /* reuse_fresh is TRUE if we are told to use a new connection by force, but
+ we only acknowledge this option if this is not a re-used connection
+ already (which happens due to follow-location or during a HTTP
+ authentication phase). */
+ if(data->set.reuse_fresh && !data->state.this_is_a_follow)
+ reuse = FALSE;
+ else
+ reuse = ConnectionExists(data, conn, &conn_temp, &force_reuse);
+
+ /* If we found a reusable connection, we may still want to
+ open a new connection if we are pipelining. */
+ if(reuse && !force_reuse && IsPipeliningPossible(data, conn_temp)) {
+ size_t pipelen = conn_temp->send_pipe->size + conn_temp->recv_pipe->size;
+ if(pipelen > 0) {
+ infof(data, "Found connection %ld, with requests in the pipe (%zu)\n",
+ conn_temp->connection_id, pipelen);
+
+ if(conn_temp->bundle->num_connections < max_host_connections &&
+ data->state.conn_cache->num_connections < max_total_connections) {
+ /* We want a new connection anyway */
+ reuse = FALSE;
+
+ infof(data, "We can reuse, but we want a new connection anyway\n");
+ }
+ }
+ }
+
+ if(reuse) {
+ /*
+ * We already have a connection for this, we got the former connection
+ * in the conn_temp variable and thus we need to cleanup the one we
+ * just allocated before we can move along and use the previously
+ * existing one.
+ */
+ conn_temp->inuse = TRUE; /* mark this as being in use so that no other
+ handle in a multi stack may nick it */
+ reuse_conn(conn, conn_temp);
+ free(conn); /* we don't need this anymore */
+ conn = conn_temp;
+ *in_connect = conn;
+
+ /* set a pointer to the hostname we display */
+ fix_hostname(data, conn, &conn->host);
+
+ infof(data, "Re-using existing connection! (#%ld) with host %s\n",
+ conn->connection_id,
+ conn->proxy.name?conn->proxy.dispname:conn->host.dispname);
+ }
+ else {
+ /* We have decided that we want a new connection. However, we may not
+ be able to do that if we have reached the limit of how many
+ connections we are allowed to open. */
+ struct connectbundle *bundle;
+
+ bundle = Curl_conncache_find_bundle(data->state.conn_cache,
+ conn->host.name);
+ if(max_host_connections > 0 && bundle &&
+ (bundle->num_connections >= max_host_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The bundle is full. Let's see if we can kill a connection. */
+ conn_candidate = find_oldest_idle_connection_in_bundle(data, bundle);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly, then kill it */
+ conn_candidate->data = data;
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ else
+ no_connections_available = TRUE;
+ }
+
+ if(max_total_connections > 0 &&
+ (data->state.conn_cache->num_connections >= max_total_connections)) {
+ struct connectdata *conn_candidate;
+
+ /* The cache is full. Let's see if we can kill a connection. */
+ conn_candidate = find_oldest_idle_connection(data);
+
+ if(conn_candidate) {
+ /* Set the connection's owner correctly, then kill it */
+ conn_candidate->data = data;
+ (void)Curl_disconnect(conn_candidate, /* dead_connection */ FALSE);
+ }
+ else
+ no_connections_available = TRUE;
+ }
+
+
+ if(no_connections_available) {
+ infof(data, "No connections available.\n");
+
+ conn_free(conn);
+ *in_connect = NULL;
+
+ result = CURLE_NO_CONNECTION_AVAILABLE;
+ goto out;
+ }
+ else {
+ /*
+ * This is a brand new connection, so let's store it in the connection
+ * cache of ours!
+ */
+ ConnectionStore(data, conn);
+ }
+ }
+
+ /* Mark the connection as used */
+ conn->inuse = TRUE;
+
+ /* Setup and init stuff before DO starts, in preparing for the transfer. */
+ do_init(conn);
+
+ /*
+ * Setup whatever necessary for a resumed transfer
+ */
+ result = setup_range(data);
+ if(result)
+ goto out;
+
+ /* Continue connectdata initialization here. */
+
+ /*
+ * Inherit the proper values from the urldata struct AFTER we have arranged
+ * the persistent connection stuff
+ */
+ conn->fread_func = data->set.fread_func;
+ conn->fread_in = data->set.in;
+ conn->seek_func = data->set.seek_func;
+ conn->seek_client = data->set.seek_client;
+
+ /*************************************************************
+ * Resolve the address of the server or proxy
+ *************************************************************/
+ result = resolve_server(data, conn, async);
+
+ out:
+
+ Curl_safefree(options);
+ Curl_safefree(passwd);
+ Curl_safefree(user);
+ Curl_safefree(proxy);
+ return result;
+}
+
+/* Curl_setup_conn() is called after the name resolve initiated in
+ * create_conn() is all done.
+ *
+ * Curl_setup_conn() also handles reused connections
+ *
+ * conn->data MUST already have been setup fine (in create_conn)
+ */
+
+CURLcode Curl_setup_conn(struct connectdata *conn,
+ bool *protocol_done)
+{
+ CURLcode result = CURLE_OK;
+ struct SessionHandle *data = conn->data;
+
+ Curl_pgrsTime(data, TIMER_NAMELOOKUP);
+
+ if(conn->handler->flags & PROTOPT_NONETWORK) {
+ /* nothing to setup when not using a network */
+ *protocol_done = TRUE;
+ return result;
+ }
+ *protocol_done = FALSE; /* default to not done */
+
+ /* set proxy_connect_closed to false unconditionally already here since it
+ is used strictly to provide extra information to a parent function in the
+ case of proxy CONNECT failures and we must make sure we don't have it
+ lingering set from a previous invoke */
+ conn->bits.proxy_connect_closed = FALSE;
+
+ /*
+ * Set user-agent. Used for HTTP, but since we can attempt to tunnel
+ * basically anything through a http proxy we can't limit this based on
+ * protocol.
+ */
+ if(data->set.str[STRING_USERAGENT]) {
+ Curl_safefree(conn->allocptr.uagent);
+ conn->allocptr.uagent =
+ aprintf("User-Agent: %s\r\n", data->set.str[STRING_USERAGENT]);
+ if(!conn->allocptr.uagent)
+ return CURLE_OUT_OF_MEMORY;
+ }
+
+ data->req.headerbytecount = 0;
+
+#ifdef CURL_DO_LINEEND_CONV
+ data->state.crlf_conversions = 0; /* reset CRLF conversion counter */
+#endif /* CURL_DO_LINEEND_CONV */
+
+ /* set start time here for timeout purposes in the connect procedure, it
+ is later set again for the progress meter purpose */
+ conn->now = Curl_tvnow();
+
+ for(;;) {
+ /* loop for CURL_SERVER_CLOSED_CONNECTION */
+
+ if(CURL_SOCKET_BAD == conn->sock[FIRSTSOCKET]) {
+ /* Try to connect only if not already connected */
+ bool connected = FALSE;
+
+ result = ConnectPlease(data, conn, &connected);
+
+ if(result && !conn->ip_addr) {
+ /* transport connection failure not related with authentication */
+ conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
+ return result;
+ }
+
+ if(connected) {
+ result = Curl_protocol_connect(conn, protocol_done);
+ if(CURLE_OK == result)
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
+ }
+ else
+ conn->bits.tcpconnect[FIRSTSOCKET] = FALSE;
+
+ /* if the connection was closed by the server while exchanging
+ authentication informations, retry with the new set
+ authentication information */
+ if(conn->bits.proxy_connect_closed) {
+ /* reset the error buffer */
+ if(data->set.errorbuffer)
+ data->set.errorbuffer[0] = '\0';
+ data->state.errorbuf = FALSE;
+ continue;
+ }
+
+ if(CURLE_OK != result)
+ return result;
+ }
+ else {
+ Curl_pgrsTime(data, TIMER_CONNECT); /* we're connected already */
+ Curl_pgrsTime(data, TIMER_APPCONNECT); /* we're connected already */
+ conn->bits.tcpconnect[FIRSTSOCKET] = TRUE;
+ *protocol_done = TRUE;
+ Curl_verboseconnect(conn);
+ Curl_updateconninfo(conn, conn->sock[FIRSTSOCKET]);
+ }
+ /* Stop the loop now */
+ break;
+ }
+
+ conn->now = Curl_tvnow(); /* time this *after* the connect is done, we
+ set this here perhaps a second time */
+
+#ifdef __EMX__
+ /*
+ * This check is quite a hack. We're calling _fsetmode to fix the problem
+ * with fwrite converting newline characters (you get mangled text files,
+ * and corrupted binary files when you download to stdout and redirect it to
+ * a file).
+ */
+
+ if((data->set.out)->_handle == NULL) {
+ _fsetmode(stdout, "b");
+ }
+#endif
+
+ return result;
+}
+
+CURLcode Curl_connect(struct SessionHandle *data,
+ struct connectdata **in_connect,
+ bool *asyncp,
+ bool *protocol_done)
+{
+ CURLcode code;
+
+ *asyncp = FALSE; /* assume synchronous resolves by default */
+
+ /* call the stuff that needs to be called */
+ code = create_conn(data, in_connect, asyncp);
+
+ if(CURLE_OK == code) {
+ /* no error */
+ if((*in_connect)->send_pipe->size || (*in_connect)->recv_pipe->size)
+ /* pipelining */
+ *protocol_done = TRUE;
+ else if(!*asyncp) {
+ /* DNS resolution is done: that's either because this is a reused
+ connection, in which case DNS was unnecessary, or because DNS
+ really did finish already (synch resolver/fast async resolve) */
+ code = Curl_setup_conn(*in_connect, protocol_done);
+ }
+ }
+
+ if(code == CURLE_NO_CONNECTION_AVAILABLE) {
+ *in_connect = NULL;
+ return code;
+ }
+
+ if(code && *in_connect) {
+ /* We're not allowed to return failure with memory left allocated
+ in the connectdata struct, free those here */
+ Curl_disconnect(*in_connect, FALSE); /* close the connection */
+ *in_connect = NULL; /* return a NULL */
+ }
+
+ return code;
+}
+
+CURLcode Curl_done(struct connectdata **connp,
+ CURLcode status, /* an error if this is called after an
+ error was detected */
+ bool premature)
+{
+ CURLcode result;
+ struct connectdata *conn;
+ struct SessionHandle *data;
+
+ DEBUGASSERT(*connp);
+
+ conn = *connp;
+ data = conn->data;
+
+ if(conn->bits.done)
+ /* Stop if Curl_done() has already been called */
+ return CURLE_OK;
+
+ Curl_getoff_all_pipelines(data, conn);
+
+ if((conn->send_pipe->size + conn->recv_pipe->size != 0 &&
+ !data->set.reuse_forbid &&
+ !conn->bits.close))
+ /* Stop if pipeline is not empty and we do not have to close
+ connection. */
+ return CURLE_OK;
+
+ conn->bits.done = TRUE; /* called just now! */
+
+ /* Cleanup possible redirect junk */
+ if(data->req.newurl) {
+ free(data->req.newurl);
+ data->req.newurl = NULL;
+ }
+ if(data->req.location) {
+ free(data->req.location);
+ data->req.location = NULL;
+ }
+
+ Curl_resolver_cancel(conn);
+
+ if(conn->dns_entry) {
+ Curl_resolv_unlock(data, conn->dns_entry); /* done with this */
+ conn->dns_entry = NULL;
+ }
+
+ switch(status) {
+ case CURLE_ABORTED_BY_CALLBACK:
+ case CURLE_READ_ERROR:
+ case CURLE_WRITE_ERROR:
+ /* When we're aborted due to a callback return code it basically have to
+ be counted as premature as there is trouble ahead if we don't. We have
+ many callbacks and protocols work differently, we could potentially do
+ this more fine-grained in the future. */
+ premature = TRUE;
+ default:
+ break;
+ }
+
+ /* this calls the protocol-specific function pointer previously set */
+ if(conn->handler->done)
+ result = conn->handler->done(conn, status, premature);
+ else
+ result = CURLE_OK;
+
+ if(Curl_pgrsDone(conn) && !result)
+ result = CURLE_ABORTED_BY_CALLBACK;
+
+ /* if the transfer was completed in a paused state there can be buffered
+ data left to write and then kill */
+ if(data->state.tempwrite) {
+ free(data->state.tempwrite);
+ data->state.tempwrite = NULL;
+ }
+
+ /* if data->set.reuse_forbid is TRUE, it means the libcurl client has
+ forced us to close this no matter what we think.
+
+ if conn->bits.close is TRUE, it means that the connection should be
+ closed in spite of all our efforts to be nice, due to protocol
+ restrictions in our or the server's end
+
+ if premature is TRUE, it means this connection was said to be DONE before
+ the entire request operation is complete and thus we can't know in what
+ state it is for re-using, so we're forced to close it. In a perfect world
+ we can add code that keep track of if we really must close it here or not,
+ but currently we have no such detail knowledge.
+ */
+ if(data->set.reuse_forbid || conn->bits.close || premature) {
+ CURLcode res2 = Curl_disconnect(conn, premature); /* close connection */
+
+ /* If we had an error already, make sure we return that one. But
+ if we got a new error, return that. */
+ if(!result && res2)
+ result = res2;
+ }
+ else {
+ /* the connection is no longer in use */
+ if(ConnectionDone(data, conn)) {
+ /* remember the most recently used connection */
+ data->state.lastconnect = conn;
+
+ infof(data, "Connection #%ld to host %s left intact\n",
+ conn->connection_id,
+ conn->bits.httpproxy?conn->proxy.dispname:conn->host.dispname);
+ }
+ else
+ data->state.lastconnect = NULL;
+ }
+
+ *connp = NULL; /* to make the caller of this function better detect that
+ this was either closed or handed over to the connection
+ cache here, and therefore cannot be used from this point on
+ */
+ Curl_free_request_state(data);
+
+ return result;
+}
+
+/*
+ * do_init() inits the readwrite session. This is inited each time (in the DO
+ * function before the protocol-specific DO functions are invoked) for a
+ * transfer, sometimes multiple times on the same SessionHandle. Make sure
+ * nothing in here depends on stuff that are setup dynamically for the
+ * transfer.
+ */
+
+static CURLcode do_init(struct connectdata *conn)
+{
+ struct SessionHandle *data = conn->data;
+ struct SingleRequest *k = &data->req;
+
+ conn->bits.done = FALSE; /* Curl_done() is not called yet */
+ conn->bits.do_more = FALSE; /* by default there's no curl_do_more() to use */
+ data->state.expect100header = FALSE;
+
+ if(data->set.opt_no_body)
+ /* in HTTP lingo, no body means using the HEAD request... */
+ data->set.httpreq = HTTPREQ_HEAD;
+ else if(HTTPREQ_HEAD == data->set.httpreq)
+ /* ... but if unset there really is no perfect method that is the
+ "opposite" of HEAD but in reality most people probably think GET
+ then. The important thing is that we can't let it remain HEAD if the
+ opt_no_body is set FALSE since then we'll behave wrong when getting
+ HTTP. */
+ data->set.httpreq = HTTPREQ_GET;
+
+ k->start = Curl_tvnow(); /* start time */
+ k->now = k->start; /* current time is now */
+ k->header = TRUE; /* assume header */
+
+ k->bytecount = 0;
+
+ k->buf = data->state.buffer;
+ k->uploadbuf = data->state.uploadbuffer;
+ k->hbufp = data->state.headerbuff;
+ k->ignorebody=FALSE;
+
+ Curl_speedinit(data);
+
+ Curl_pgrsSetUploadCounter(data, 0);
+ Curl_pgrsSetDownloadCounter(data, 0);
+
+ return CURLE_OK;
+}
+
+/*
+ * do_complete is called when the DO actions are complete.
+ *
+ * We init chunking and trailer bits to their default values here immediately
+ * before receiving any header data for the current request in the pipeline.
+ */
+static void do_complete(struct connectdata *conn)
+{
+ conn->data->req.chunk=FALSE;
+ conn->data->req.maxfd = (conn->sockfd>conn->writesockfd?
+ conn->sockfd:conn->writesockfd)+1;
+ Curl_pgrsTime(conn->data, TIMER_PRETRANSFER);
+}
+
+CURLcode Curl_do(struct connectdata **connp, bool *done)
+{
+ CURLcode result=CURLE_OK;
+ struct connectdata *conn = *connp;
+ struct SessionHandle *data = conn->data;
+
+ if(conn->handler->do_it) {
+ /* generic protocol-specific function pointer set in curl_connect() */
+ result = conn->handler->do_it(conn, done);
+
+ /* This was formerly done in transfer.c, but we better do it here */
+ if((CURLE_SEND_ERROR == result) && conn->bits.reuse) {
+ /*
+ * If the connection is using an easy handle, call reconnect
+ * to re-establish the connection. Otherwise, let the multi logic
+ * figure out how to re-establish the connection.
+ */
+ if(!data->multi) {
+ result = Curl_reconnect_request(connp);
+
+ if(result == CURLE_OK) {
+ /* ... finally back to actually retry the DO phase */
+ conn = *connp; /* re-assign conn since Curl_reconnect_request
+ creates a new connection */
+ result = conn->handler->do_it(conn, done);
+ }
+ }
+ else
+ return result;
+ }
+
+ if((result == CURLE_OK) && *done)
+ /* do_complete must be called after the protocol-specific DO function */
+ do_complete(conn);
+ }
+ return result;
+}
+
+/*
+ * Curl_do_more() is called during the DO_MORE multi state. It is basically a
+ * second stage DO state which (wrongly) was introduced to support FTP's
+ * second connection.
+ *
+ * TODO: A future libcurl should be able to work away this state.
+ *
+ * 'complete' can return 0 for incomplete, 1 for done and -1 for go back to
+ * DOING state there's more work to do!
+ */
+
+CURLcode Curl_do_more(struct connectdata *conn, int *complete)
+{
+ CURLcode result=CURLE_OK;
+
+ *complete = 0;
+
+ if(conn->handler->do_more)
+ result = conn->handler->do_more(conn, complete);
+
+ if(!result && (*complete == 1))
+ /* do_complete must be called after the protocol-specific DO function */
+ do_complete(conn);
+
+ return result;
+}
+
diff --git a/libs/libcurl/src/url.h b/libs/libcurl/src/url.h
new file mode 100644
index 0000000000..418413c484
--- /dev/null
+++ b/libs/libcurl/src/url.h
@@ -0,0 +1,82 @@
+#ifndef HEADER_CURL_URL_H
+#define HEADER_CURL_URL_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"
+
+/*
+ * Prototypes for library-wide functions provided by url.c
+ */
+
+CURLcode Curl_open(struct SessionHandle **curl);
+CURLcode Curl_init_userdefined(struct UserDefined *set);
+CURLcode Curl_setopt(struct SessionHandle *data, CURLoption option,
+ va_list arg);
+CURLcode Curl_dupset(struct SessionHandle * dst, struct SessionHandle * src);
+void Curl_freeset(struct SessionHandle * data);
+CURLcode Curl_close(struct SessionHandle *data); /* opposite of curl_open() */
+CURLcode Curl_connect(struct SessionHandle *, struct connectdata **,
+ bool *async, bool *protocol_connect);
+CURLcode Curl_do(struct connectdata **, bool *done);
+CURLcode Curl_do_more(struct connectdata *, int *completed);
+CURLcode Curl_done(struct connectdata **, CURLcode, bool premature);
+CURLcode Curl_disconnect(struct connectdata *, bool dead_connection);
+CURLcode Curl_protocol_connect(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_connecting(struct connectdata *conn, bool *done);
+CURLcode Curl_protocol_doing(struct connectdata *conn, bool *done);
+CURLcode Curl_setup_conn(struct connectdata *conn,
+ bool *protocol_done);
+void Curl_free_request_state(struct SessionHandle *data);
+
+int Curl_protocol_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+int Curl_doing_getsock(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+bool Curl_isPipeliningEnabled(const struct SessionHandle *handle);
+CURLcode Curl_addHandleToPipeline(struct SessionHandle *handle,
+ struct curl_llist *pipeline);
+int Curl_removeHandleFromPipeline(struct SessionHandle *handle,
+ struct curl_llist *pipeline);
+/* remove the specified connection from all (possible) pipelines and related
+ queues */
+void Curl_getoff_all_pipelines(struct SessionHandle *data,
+ struct connectdata *conn);
+
+void Curl_close_connections(struct SessionHandle *data);
+
+#define CURL_DEFAULT_PROXY_PORT 1080 /* default proxy port unless specified */
+#define CURL_DEFAULT_SOCKS5_GSSAPI_SERVICE "rcmd" /* default socks5 gssapi
+ service */
+
+CURLcode Curl_connected_proxy(struct connectdata *conn);
+
+#ifdef CURL_DISABLE_VERBOSE_STRINGS
+#define Curl_verboseconnect(x) Curl_nop_stmt
+#else
+void Curl_verboseconnect(struct connectdata *conn);
+#endif
+
+
+#endif /* HEADER_CURL_URL_H */
diff --git a/libs/libcurl/src/urldata.h b/libs/libcurl/src/urldata.h
new file mode 100644
index 0000000000..ebaaf6ff4f
--- /dev/null
+++ b/libs/libcurl/src/urldata.h
@@ -0,0 +1,1648 @@
+#ifndef HEADER_CURL_URLDATA_H
+#define HEADER_CURL_URLDATA_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.
+ *
+ ***************************************************************************/
+
+/* This file is for lib internal stuff */
+
+#include "curl_setup.h"
+
+#define PORT_FTP 21
+#define PORT_FTPS 990
+#define PORT_TELNET 23
+#define PORT_HTTP 80
+#define PORT_HTTPS 443
+#define PORT_DICT 2628
+#define PORT_LDAP 389
+#define PORT_LDAPS 636
+#define PORT_TFTP 69
+#define PORT_SSH 22
+#define PORT_IMAP 143
+#define PORT_IMAPS 993
+#define PORT_POP3 110
+#define PORT_POP3S 995
+#define PORT_SMTP 25
+#define PORT_SMTPS 465 /* sometimes called SSMTP */
+#define PORT_RTSP 554
+#define PORT_RTMP 1935
+#define PORT_RTMPT PORT_HTTP
+#define PORT_RTMPS PORT_HTTPS
+#define PORT_GOPHER 70
+
+#define DICT_MATCH "/MATCH:"
+#define DICT_MATCH2 "/M:"
+#define DICT_MATCH3 "/FIND:"
+#define DICT_DEFINE "/DEFINE:"
+#define DICT_DEFINE2 "/D:"
+#define DICT_DEFINE3 "/LOOKUP:"
+
+#define CURL_DEFAULT_USER "anonymous"
+#define CURL_DEFAULT_PASSWORD "ftp@example.com"
+
+#define DEFAULT_CONNCACHE_SIZE 5
+
+/* length of longest IPv6 address string including the trailing null */
+#define MAX_IPADR_LEN sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")
+
+/* Default FTP/IMAP etc response timeout in milliseconds.
+ Symbian OS panics when given a timeout much greater than 1/2 hour.
+*/
+#define RESP_TIMEOUT (1800*1000)
+
+#include "cookie.h"
+#include "formdata.h"
+
+#ifdef USE_SSLEAY
+#ifdef USE_OPENSSL
+#include <openssl/rsa.h>
+#include <openssl/crypto.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <openssl/engine.h>
+#endif
+#ifdef HAVE_OPENSSL_PKCS12_H
+#include <openssl/pkcs12.h>
+#endif
+#else /* SSLeay-style includes */
+#include <rsa.h>
+#include <crypto.h>
+#include <x509.h>
+#include <pem.h>
+#include <ssl.h>
+#include <err.h>
+#ifdef HAVE_OPENSSL_ENGINE_H
+#include <engine.h>
+#endif
+#ifdef HAVE_OPENSSL_PKCS12_H
+#include <pkcs12.h>
+#endif
+#endif /* USE_OPENSSL */
+#ifdef USE_GNUTLS
+#error Configuration error; cannot use GnuTLS *and* OpenSSL.
+#endif
+#endif /* USE_SSLEAY */
+
+#ifdef USE_GNUTLS
+#include <gnutls/gnutls.h>
+#endif
+
+#ifdef USE_POLARSSL
+#include <polarssl/ssl.h>
+#include <polarssl/version.h>
+#if POLARSSL_VERSION_NUMBER<0x01010000
+#include <polarssl/havege.h>
+#else
+#include <polarssl/entropy.h>
+#include <polarssl/ctr_drbg.h>
+#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+#endif /* USE_POLARSSL */
+
+#ifdef USE_CYASSL
+#undef OCSP_REQUEST /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
+#undef OCSP_RESPONSE /* avoid cyassl/openssl/ssl.h clash with wincrypt.h */
+#include <cyassl/openssl/ssl.h>
+#endif
+
+#ifdef USE_NSS
+#include <nspr.h>
+#include <pk11pub.h>
+#endif
+
+#ifdef USE_QSOSSL
+#include <qsossl.h>
+#endif
+
+#ifdef USE_GSKIT
+#include <gskssl.h>
+#endif
+
+#ifdef USE_AXTLS
+#include <axTLS/ssl.h>
+#undef malloc
+#undef calloc
+#undef realloc
+#endif /* USE_AXTLS */
+
+#ifdef USE_SCHANNEL
+#include "curl_sspi.h"
+#include <schnlsp.h>
+#include <schannel.h>
+#endif
+
+#ifdef USE_DARWINSSL
+#include <Security/Security.h>
+/* For some reason, when building for iOS, the omnibus header above does
+ * not include SecureTransport.h as of iOS SDK 5.1. */
+#include <Security/SecureTransport.h>
+#endif
+
+#ifdef HAVE_NETINET_IN_H
+#include <netinet/in.h>
+#endif
+
+#include "timeval.h"
+
+#ifdef HAVE_ZLIB_H
+#include <zlib.h> /* for content-encoding */
+#ifdef __SYMBIAN32__
+/* zlib pollutes the namespace with this definition */
+#undef WIN32
+#endif
+#endif
+
+#include <curl/curl.h>
+
+#include "http_chunks.h" /* for the structs and enum stuff */
+#include "hostip.h"
+#include "hash.h"
+#include "splay.h"
+
+#include "imap.h"
+#include "pop3.h"
+#include "smtp.h"
+#include "ftp.h"
+#include "file.h"
+#include "ssh.h"
+#include "http.h"
+#include "rtsp.h"
+#include "wildcard.h"
+#include "multihandle.h"
+
+#ifdef HAVE_GSSAPI
+# ifdef HAVE_GSSGNU
+# include <gss.h>
+# elif defined HAVE_GSSMIT
+# include <gssapi/gssapi.h>
+# include <gssapi/gssapi_generic.h>
+# else
+# include <gssapi.h>
+# endif
+#endif
+
+#ifdef HAVE_LIBSSH2_H
+#include <libssh2.h>
+#include <libssh2_sftp.h>
+#endif /* HAVE_LIBSSH2_H */
+
+/* Download buffer size, keep it fairly big for speed reasons */
+#undef BUFSIZE
+#define BUFSIZE CURL_MAX_WRITE_SIZE
+
+/* Initial size of the buffer to store headers in, it'll be enlarged in case
+ of need. */
+#define HEADERSIZE 256
+
+#define CURLEASY_MAGIC_NUMBER 0xc0dedbadU
+
+/* Some convenience macros to get the larger/smaller value out of two given.
+ We prefix with CURL to prevent name collisions. */
+#define CURLMAX(x,y) ((x)>(y)?(x):(y))
+#define CURLMIN(x,y) ((x)<(y)?(x):(y))
+
+
+#ifdef HAVE_GSSAPI
+/* Types needed for krb5-ftp connections */
+struct krb5buffer {
+ void *data;
+ size_t size;
+ size_t index;
+ int eof_flag;
+};
+
+enum protection_level {
+ PROT_NONE, /* first in list */
+ PROT_CLEAR,
+ PROT_SAFE,
+ PROT_CONFIDENTIAL,
+ PROT_PRIVATE,
+ PROT_CMD,
+ PROT_LAST /* last in list */
+};
+#endif
+
+#ifdef USE_SCHANNEL
+/* Structs to store Schannel handles */
+struct curl_schannel_cred {
+ CredHandle cred_handle;
+ TimeStamp time_stamp;
+ int refcount;
+ bool cached;
+};
+
+struct curl_schannel_ctxt {
+ CtxtHandle ctxt_handle;
+ TimeStamp time_stamp;
+};
+#endif
+
+/* enum for the nonblocking SSL connection state machine */
+typedef enum {
+ ssl_connect_1,
+ ssl_connect_2,
+ ssl_connect_2_reading,
+ ssl_connect_2_writing,
+ ssl_connect_3,
+ ssl_connect_done
+} ssl_connect_state;
+
+typedef enum {
+ ssl_connection_none,
+ ssl_connection_negotiating,
+ ssl_connection_complete
+} ssl_connection_state;
+
+/* struct for data related to each SSL connection */
+struct ssl_connect_data {
+ /* Use ssl encrypted communications TRUE/FALSE, not necessarily using it atm
+ but at least asked to or meaning to use it. See 'state' for the exact
+ current state of the connection. */
+ bool use;
+ ssl_connection_state state;
+#ifdef USE_SSLEAY
+ /* these ones requires specific SSL-types */
+ SSL_CTX* ctx;
+ SSL* handle;
+ X509* server_cert;
+ ssl_connect_state connecting_state;
+#endif /* USE_SSLEAY */
+#ifdef USE_GNUTLS
+ gnutls_session session;
+ gnutls_certificate_credentials cred;
+#ifdef USE_TLS_SRP
+ gnutls_srp_client_credentials srp_client_cred;
+#endif
+ ssl_connect_state connecting_state;
+#endif /* USE_GNUTLS */
+#ifdef USE_POLARSSL
+#if POLARSSL_VERSION_NUMBER<0x01010000
+ havege_state hs;
+#else
+ /* from v1.1.0, use ctr_drbg and entropy */
+ ctr_drbg_context ctr_drbg;
+ entropy_context entropy;
+#endif /* POLARSSL_VERSION_NUMBER<0x01010000 */
+ ssl_context ssl;
+ ssl_session ssn;
+ int server_fd;
+ x509_cert cacert;
+ x509_cert clicert;
+ x509_crl crl;
+ rsa_context rsa;
+ ssl_connect_state connecting_state;
+#endif /* USE_POLARSSL */
+#ifdef USE_CYASSL
+ SSL_CTX* ctx;
+ SSL* handle;
+ ssl_connect_state connecting_state;
+#endif /* USE_CYASSL */
+#ifdef USE_NSS
+ PRFileDesc *handle;
+ char *client_nickname;
+ struct SessionHandle *data;
+ struct curl_llist *obj_list;
+ PK11GenericObject *obj_clicert;
+#endif /* USE_NSS */
+#ifdef USE_QSOSSL
+ SSLHandle *handle;
+#endif /* USE_QSOSSL */
+#ifdef USE_GSKIT
+ gsk_handle handle;
+ int iocport;
+ ssl_connect_state connecting_state;
+#endif
+#ifdef USE_AXTLS
+ SSL_CTX* ssl_ctx;
+ SSL* ssl;
+ ssl_connect_state connecting_state;
+#endif /* USE_AXTLS */
+#ifdef USE_SCHANNEL
+ struct curl_schannel_cred *cred;
+ struct curl_schannel_ctxt *ctxt;
+ SecPkgContext_StreamSizes stream_sizes;
+ ssl_connect_state connecting_state;
+ size_t encdata_length, decdata_length;
+ size_t encdata_offset, decdata_offset;
+ unsigned char *encdata_buffer, *decdata_buffer;
+ unsigned long req_flags, ret_flags;
+#endif /* USE_SCHANNEL */
+#ifdef USE_DARWINSSL
+ SSLContextRef ssl_ctx;
+ curl_socket_t ssl_sockfd;
+ ssl_connect_state connecting_state;
+ bool ssl_direction; /* true if writing, false if reading */
+ size_t ssl_write_buffered_length;
+#endif /* USE_DARWINSSL */
+};
+
+struct ssl_config_data {
+ long version; /* what version the client wants to use */
+ long certverifyresult; /* result from the certificate verification */
+
+ bool verifypeer; /* set TRUE if this is desired */
+ bool verifyhost; /* set TRUE if CN/SAN must match hostname */
+ char *CApath; /* certificate dir (doesn't work on windows) */
+ char *CAfile; /* certificate to verify peer against */
+ const char *CRLfile; /* CRL to check certificate revocation */
+ const char *issuercert;/* optional issuer certificate filename */
+ char *random_file; /* path to file containing "random" data */
+ char *egdsocket; /* path to file containing the EGD daemon socket */
+ char *cipher_list; /* list of ciphers to use */
+ size_t max_ssl_sessions; /* SSL session id cache size */
+ curl_ssl_ctx_callback fsslctx; /* function to initialize ssl ctx */
+ void *fsslctxp; /* parameter for call back */
+ bool sessionid; /* cache session IDs or not */
+ bool certinfo; /* gather lots of certificate info */
+
+#ifdef USE_TLS_SRP
+ char *username; /* TLS username (for, e.g., SRP) */
+ char *password; /* TLS password (for, e.g., SRP) */
+ enum CURL_TLSAUTH authtype; /* TLS authentication type (default SRP) */
+#endif
+};
+
+/* information stored about one single SSL session */
+struct curl_ssl_session {
+ char *name; /* host name for which this ID was used */
+ void *sessionid; /* as returned from the SSL layer */
+ size_t idsize; /* if known, otherwise 0 */
+ long age; /* just a number, the higher the more recent */
+ unsigned short remote_port; /* remote port to connect to */
+ struct ssl_config_data ssl_config; /* setup for this session */
+};
+
+/* Struct used for Digest challenge-response authentication */
+struct digestdata {
+ char *nonce;
+ char *cnonce;
+ char *realm;
+ int algo;
+ bool stale; /* set true for re-negotiation */
+ char *opaque;
+ char *qop;
+ char *algorithm;
+ int nc; /* nounce count */
+};
+
+typedef enum {
+ NTLMSTATE_NONE,
+ NTLMSTATE_TYPE1,
+ NTLMSTATE_TYPE2,
+ NTLMSTATE_TYPE3,
+ NTLMSTATE_LAST
+} curlntlm;
+
+#ifdef USE_WINDOWS_SSPI
+#include "curl_sspi.h"
+#endif
+
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+#include <iconv.h>
+#endif
+
+/* Struct used for NTLM challenge-response authentication */
+struct ntlmdata {
+ curlntlm state;
+#ifdef USE_WINDOWS_SSPI
+ CredHandle handle;
+ CtxtHandle c_handle;
+ SEC_WINNT_AUTH_IDENTITY identity;
+ SEC_WINNT_AUTH_IDENTITY *p_identity;
+ int has_handles;
+ void *type_2;
+ unsigned long n_type_2;
+#else
+ unsigned int flags;
+ unsigned char nonce[8];
+#endif
+};
+
+#ifdef USE_HTTP_NEGOTIATE
+struct negotiatedata {
+ /* when doing Negotiate we first need to receive an auth token and then we
+ need to send our header */
+ enum { GSS_AUTHNONE, GSS_AUTHRECV, GSS_AUTHSENT } state;
+ bool gss; /* Whether we're processing GSS-Negotiate or Negotiate */
+ const char* protocol; /* "GSS-Negotiate" or "Negotiate" */
+#ifdef HAVE_GSSAPI
+ OM_uint32 status;
+ gss_ctx_id_t context;
+ gss_name_t server_name;
+ gss_buffer_desc output_token;
+#else
+#ifdef USE_WINDOWS_SSPI
+ DWORD status;
+ CtxtHandle *context;
+ CredHandle *credentials;
+ char server_name[1024];
+ size_t max_token_length;
+ BYTE *output_token;
+ size_t output_token_length;
+#endif
+#endif
+};
+#endif
+
+
+/*
+ * Boolean values that concerns this connection.
+ */
+struct ConnectBits {
+ bool close; /* if set, we close the connection after this request */
+ bool reuse; /* if set, this is a re-used connection */
+ bool proxy; /* if set, this transfer is done through a proxy - any type */
+ bool httpproxy; /* if set, this transfer is done through a http proxy */
+ bool user_passwd; /* do we use user+password for this connection? */
+ bool proxy_user_passwd; /* user+password for the proxy? */
+ bool ipv6_ip; /* we communicate with a remote site specified with pure IPv6
+ IP address */
+ bool ipv6; /* we communicate with a site using an IPv6 address */
+
+ bool do_more; /* this is set TRUE if the ->curl_do_more() function is
+ supposed to be called, after ->curl_do() */
+ bool tcpconnect[2]; /* the TCP layer (or similar) is connected, this is set
+ the first time on the first connect function call */
+ bool protoconnstart;/* the protocol layer has STARTED its operation after
+ the TCP layer connect */
+
+ bool retry; /* this connection is about to get closed and then
+ re-attempted at another connection. */
+ bool tunnel_proxy; /* if CONNECT is used to "tunnel" through the proxy.
+ This is implicit when SSL-protocols are used through
+ proxies, but can also be enabled explicitly by
+ apps */
+ bool authneg; /* TRUE when the auth phase has started, which means
+ that we are creating a request with an auth header,
+ but it is not the final request in the auth
+ negotiation. */
+ bool rewindaftersend;/* TRUE when the sending couldn't be stopped even
+ though it will be discarded. When the whole send
+ operation is done, we must call the data rewind
+ callback. */
+ bool ftp_use_epsv; /* As set with CURLOPT_FTP_USE_EPSV, but if we find out
+ EPSV doesn't work we disable it for the forthcoming
+ requests */
+
+ bool ftp_use_eprt; /* As set with CURLOPT_FTP_USE_EPRT, but if we find out
+ EPRT doesn't work we disable it for the forthcoming
+ requests */
+ bool netrc; /* name+password provided by netrc */
+ bool userpwd_in_url; /* name+password found in url */
+
+ bool done; /* set to FALSE when Curl_do() is called and set to TRUE
+ when Curl_done() is called, to prevent Curl_done() to
+ get invoked twice when the multi interface is
+ used. */
+ bool stream_was_rewound; /* Indicates that the stream was rewound after a
+ request read past the end of its response byte
+ boundary */
+ bool proxy_connect_closed; /* set true if a proxy disconnected the
+ connection in a CONNECT request with auth, so
+ that libcurl should reconnect and continue. */
+ bool bound; /* set true if bind() has already been done on this socket/
+ connection */
+ bool type_set; /* type= was used in the URL */
+};
+
+struct hostname {
+ char *rawalloc; /* allocated "raw" version of the name */
+ char *encalloc; /* allocated IDN-encoded version of the name */
+ char *name; /* name to use internally, might be encoded, might be raw */
+ const char *dispname; /* name to display, as 'name' might be encoded */
+};
+
+/*
+ * Flags on the keepon member of the Curl_transfer_keeper
+ */
+
+#define KEEP_NONE 0
+#define KEEP_RECV (1<<0) /* there is or may be data to read */
+#define KEEP_SEND (1<<1) /* there is or may be data to write */
+#define KEEP_RECV_HOLD (1<<2) /* when set, no reading should be done but there
+ might still be data to read */
+#define KEEP_SEND_HOLD (1<<3) /* when set, no writing should be done but there
+ might still be data to write */
+#define KEEP_RECV_PAUSE (1<<4) /* reading is paused */
+#define KEEP_SEND_PAUSE (1<<5) /* writing is paused */
+
+#define KEEP_RECVBITS (KEEP_RECV | KEEP_RECV_HOLD | KEEP_RECV_PAUSE)
+#define KEEP_SENDBITS (KEEP_SEND | KEEP_SEND_HOLD | KEEP_SEND_PAUSE)
+
+
+#ifdef HAVE_LIBZ
+typedef enum {
+ ZLIB_UNINIT, /* uninitialized */
+ ZLIB_INIT, /* initialized */
+ ZLIB_GZIP_HEADER, /* reading gzip header */
+ ZLIB_GZIP_INFLATING, /* inflating gzip stream */
+ ZLIB_INIT_GZIP /* initialized in transparent gzip mode */
+} zlibInitState;
+#endif
+
+#ifdef CURLRES_ASYNCH
+struct Curl_async {
+ char *hostname;
+ int port;
+ struct Curl_dns_entry *dns;
+ bool done; /* set TRUE when the lookup is complete */
+ int status; /* if done is TRUE, this is the status from the callback */
+ void *os_specific; /* 'struct thread_data' for Windows */
+};
+#endif
+
+#define FIRSTSOCKET 0
+#define SECONDARYSOCKET 1
+
+/* These function pointer types are here only to allow easier typecasting
+ within the source when we need to cast between data pointers (such as NULL)
+ and function pointers. */
+typedef CURLcode (*Curl_do_more_func)(struct connectdata *, int *);
+typedef CURLcode (*Curl_done_func)(struct connectdata *, CURLcode, bool);
+
+
+enum expect100 {
+ EXP100_SEND_DATA, /* enough waiting, just send the body now */
+ EXP100_AWAITING_CONTINUE, /* waiting for the 100 Continue header */
+ EXP100_SENDING_REQUEST, /* still sending the request but will wait for
+ the 100 header once done with the request */
+ EXP100_FAILED /* used on 417 Expectation Failed */
+};
+
+/*
+ * Request specific data in the easy handle (SessionHandle). Previously,
+ * these members were on the connectdata struct but since a conn struct may
+ * now be shared between different SessionHandles, we store connection-specific
+ * data here. This struct only keeps stuff that's interesting for *this*
+ * request, as it will be cleared between multiple ones
+ */
+struct SingleRequest {
+ curl_off_t size; /* -1 if unknown at this point */
+ curl_off_t *bytecountp; /* return number of bytes read or NULL */
+
+ curl_off_t maxdownload; /* in bytes, the maximum amount of data to fetch,
+ -1 means unlimited */
+ curl_off_t *writebytecountp; /* return number of bytes written or NULL */
+
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
+
+ long headerbytecount; /* only count received headers */
+ long deductheadercount; /* this amount of bytes doesn't count when we check
+ if anything has been transferred at the end of a
+ connection. We use this counter to make only a
+ 100 reply (without a following second response
+ code) result in a CURLE_GOT_NOTHING error code */
+
+ struct timeval start; /* transfer started at this time */
+ struct timeval now; /* current time */
+ bool header; /* incoming data has HTTP header */
+ enum {
+ HEADER_NORMAL, /* no bad header at all */
+ HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
+ is normal data */
+ HEADER_ALLBAD /* all was believed to be header */
+ } badheader; /* the header was deemed bad and will be
+ written as body */
+ int headerline; /* counts header lines to better track the
+ first one */
+ char *hbufp; /* points at *end* of header line */
+ size_t hbuflen;
+ char *str; /* within buf */
+ char *str_start; /* within buf */
+ char *end_ptr; /* within buf */
+ char *p; /* within headerbuff */
+ bool content_range; /* set TRUE if Content-Range: was found */
+ curl_off_t offset; /* possible resume offset read from the
+ Content-Range: header */
+ int httpcode; /* error code from the 'HTTP/1.? XXX' or
+ 'RTSP/1.? XXX' line */
+ struct timeval start100; /* time stamp to wait for the 100 code from */
+ enum expect100 exp100; /* expect 100 continue state */
+
+ int auto_decoding; /* What content encoding. sec 3.5, RFC2616. */
+
+#define IDENTITY 0 /* No encoding */
+#define DEFLATE 1 /* zlib deflate [RFC 1950 & 1951] */
+#define GZIP 2 /* gzip algorithm [RFC 1952] */
+#define COMPRESS 3 /* Not handled, added for completeness */
+
+#ifdef HAVE_LIBZ
+ zlibInitState zlib_init; /* possible zlib init state;
+ undefined if Content-Encoding header. */
+ z_stream z; /* State structure for zlib. */
+#endif
+
+ time_t timeofdoc;
+ long bodywrites;
+
+ char *buf;
+ char *uploadbuf;
+ curl_socket_t maxfd;
+
+ int keepon;
+
+ bool upload_done; /* set to TRUE when doing chunked transfer-encoding upload
+ and we're uploading the last chunk */
+
+ bool ignorebody; /* we read a response-body but we ignore it! */
+ bool ignorecl; /* This HTTP response has no body so we ignore the Content-
+ Length: header */
+
+ char *location; /* This points to an allocated version of the Location:
+ header data */
+ char *newurl; /* Set to the new URL to use when a redirect or a retry is
+ wanted */
+
+ /* 'upload_present' is used to keep a byte counter of how much data there is
+ still left in the buffer, aimed for upload. */
+ ssize_t upload_present;
+
+ /* 'upload_fromhere' is used as a read-pointer when we uploaded parts of a
+ buffer, so the next read should read from where this pointer points to,
+ and the 'upload_present' contains the number of bytes available at this
+ position */
+ char *upload_fromhere;
+
+ bool chunk; /* if set, this is a chunked transfer-encoding */
+ bool upload_chunky; /* set TRUE if we are doing chunked transfer-encoding
+ on upload */
+ bool getheader; /* TRUE if header parsing is wanted */
+
+ bool forbidchunk; /* used only to explicitly forbid chunk-upload for
+ specific upload buffers. See readmoredata() in
+ http.c for details. */
+
+ void *protop; /* Allocated protocol-specific data. Each protocol
+ handler makes sure this points to data it needs. */
+};
+
+/*
+ * Specific protocol handler.
+ */
+
+struct Curl_handler {
+ const char * scheme; /* URL scheme name. */
+
+ /* Complement to setup_connection_internals(). */
+ CURLcode (*setup_connection)(struct connectdata *);
+
+ /* These two functions MUST be set to be protocol dependent */
+ CURLcode (*do_it)(struct connectdata *, bool *done);
+ Curl_done_func done;
+
+ /* If the curl_do() function is better made in two halves, this
+ * curl_do_more() function will be called afterwards, if set. For example
+ * for doing the FTP stuff after the PASV/PORT command.
+ */
+ Curl_do_more_func do_more;
+
+ /* This function *MAY* be set to a protocol-dependent function that is run
+ * after the connect() and everything is done, as a step in the connection.
+ * The 'done' pointer points to a bool that should be set to TRUE if the
+ * function completes before return. If it doesn't complete, the caller
+ * should call the curl_connecting() function until it is.
+ */
+ CURLcode (*connect_it)(struct connectdata *, bool *done);
+
+ /* See above. Currently only used for FTP. */
+ CURLcode (*connecting)(struct connectdata *, bool *done);
+ CURLcode (*doing)(struct connectdata *, bool *done);
+
+ /* Called from the multi interface during the PROTOCONNECT phase, and it
+ should then return a proper fd set */
+ int (*proto_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DOING phase, and it should
+ then return a proper fd set */
+ int (*doing_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DO_MORE phase, and it should
+ then return a proper fd set */
+ int (*domore_getsock)(struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* Called from the multi interface during the DO_DONE, PERFORM and
+ WAITPERFORM phases, and it should then return a proper fd set. Not setting
+ this will make libcurl use the generic default one. */
+ int (*perform_getsock)(const struct connectdata *conn,
+ curl_socket_t *socks,
+ int numsocks);
+
+ /* This function *MAY* be set to a protocol-dependent function that is run
+ * by the curl_disconnect(), as a step in the disconnection. If the handler
+ * is called because the connection has been considered dead, dead_connection
+ * is set to TRUE.
+ */
+ CURLcode (*disconnect)(struct connectdata *, bool dead_connection);
+
+ /* If used, this function gets called from transfer.c:readwrite_data() to
+ allow the protocol to do extra reads/writes */
+ CURLcode (*readwrite)(struct SessionHandle *data, struct connectdata *conn,
+ ssize_t *nread, bool *readmore);
+
+ long defport; /* Default port. */
+ unsigned int protocol; /* See CURLPROTO_* */
+ unsigned int flags; /* Extra particular characteristics, see PROTOPT_* */
+};
+
+#define PROTOPT_NONE 0 /* nothing extra */
+#define PROTOPT_SSL (1<<0) /* uses SSL */
+#define PROTOPT_DUAL (1<<1) /* this protocol uses two connections */
+#define PROTOPT_CLOSEACTION (1<<2) /* need action before socket close */
+/* some protocols will have to call the underlying functions without regard to
+ what exact state the socket signals. IE even if the socket says "readable",
+ the send function might need to be called while uploading, or vice versa.
+*/
+#define PROTOPT_DIRLOCK (1<<3)
+#define PROTOPT_NONETWORK (1<<4) /* protocol doesn't use the network! */
+#define PROTOPT_NEEDSPWD (1<<5) /* needs a password, and if none is set it
+ gets a default */
+#define PROTOPT_NOURLQUERY (1<<6) /* protocol can't handle
+ url query strings (?foo=bar) ! */
+
+
+/* return the count of bytes sent, or -1 on error */
+typedef ssize_t (Curl_send)(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ const void *buf, /* data to write */
+ size_t len, /* max amount to write */
+ CURLcode *err); /* error to return */
+
+/* return the count of bytes read, or -1 on error */
+typedef ssize_t (Curl_recv)(struct connectdata *conn, /* connection data */
+ int sockindex, /* socketindex */
+ char *buf, /* store data here */
+ size_t len, /* max amount to read */
+ CURLcode *err); /* error to return */
+
+/*
+ * The connectdata struct contains all fields and variables that should be
+ * unique for an entire connection.
+ */
+struct connectdata {
+ /* 'data' is the CURRENT SessionHandle using this connection -- take great
+ caution that this might very well vary between different times this
+ connection is used! */
+ struct SessionHandle *data;
+
+ /* chunk is for HTTP chunked encoding, but is in the general connectdata
+ struct only because we can do just about any protocol through a HTTP proxy
+ and a HTTP proxy may in fact respond using chunked encoding */
+ struct Curl_chunker chunk;
+
+ curl_closesocket_callback fclosesocket; /* function closing the socket(s) */
+ void *closesocket_client;
+
+ bool inuse; /* This is a marker for the connection cache logic. If this is
+ TRUE this handle is being used by an easy handle and cannot
+ be used by any other easy handle without careful
+ consideration (== only for pipelining). */
+
+ /**** Fields set when inited and not modified again */
+ long connection_id; /* Contains a unique number to make it easier to
+ track the connections in the log output */
+
+ /* 'dns_entry' is the particular host we use. This points to an entry in the
+ DNS cache and it will not get pruned while locked. It gets unlocked in
+ Curl_done(). This entry will be NULL if the connection is re-used as then
+ there is no name resolve done. */
+ struct Curl_dns_entry *dns_entry;
+
+ /* 'ip_addr' is the particular IP we connected to. It points to a struct
+ within the DNS cache, so this pointer is only valid as long as the DNS
+ cache entry remains locked. It gets unlocked in Curl_done() */
+ Curl_addrinfo *ip_addr;
+
+ /* 'ip_addr_str' is the ip_addr data as a human readable string.
+ It remains available as long as the connection does, which is longer than
+ the ip_addr itself. */
+ char ip_addr_str[MAX_IPADR_LEN];
+
+ unsigned int scope; /* address scope for IPv6 */
+
+ int socktype; /* SOCK_STREAM or SOCK_DGRAM */
+
+ struct hostname host;
+ struct hostname proxy;
+
+ long port; /* which port to use locally */
+ unsigned short remote_port; /* what remote port to connect to,
+ not the proxy port! */
+
+ /* 'primary_ip' and 'primary_port' get filled with peer's numerical
+ ip address and port number whenever an outgoing connection is
+ *attempted* from the primary socket to a remote address. When more
+ than one address is tried for a connection these will hold data
+ for the last attempt. When the connection is actually established
+ these are updated with data which comes directly from the socket. */
+
+ char primary_ip[MAX_IPADR_LEN];
+ long primary_port;
+
+ /* 'local_ip' and 'local_port' get filled with local's numerical
+ ip address and port number whenever an outgoing connection is
+ **established** from the primary socket to a remote address. */
+
+ char local_ip[MAX_IPADR_LEN];
+ long local_port;
+
+ char *user; /* user name string, allocated */
+ char *passwd; /* password string, allocated */
+ char *options; /* options string, allocated */
+
+ char *xoauth2_bearer; /* bearer token for xoauth2, allocated */
+
+ char *proxyuser; /* proxy user name string, allocated */
+ char *proxypasswd; /* proxy password string, allocated */
+ curl_proxytype proxytype; /* what kind of proxy that is in use */
+
+ int httpversion; /* the HTTP version*10 reported by the server */
+ int rtspversion; /* the RTSP version*10 reported by the server */
+
+ struct timeval now; /* "current" time */
+ struct timeval created; /* creation time */
+ curl_socket_t sock[2]; /* two sockets, the second is used for the data
+ transfer when doing FTP */
+ bool sock_accepted[2]; /* TRUE if the socket on this index was created with
+ accept() */
+ Curl_recv *recv[2];
+ Curl_send *send[2];
+
+ struct ssl_connect_data ssl[2]; /* this is for ssl-stuff */
+ struct ssl_config_data ssl_config;
+
+ struct ConnectBits bits; /* various state-flags for this connection */
+
+ /* connecttime: when connect() is called on the current IP address. Used to
+ be able to track when to move on to try next IP - but only when the multi
+ interface is used. */
+ struct timeval connecttime;
+ /* The two fields below get set in Curl_connecthost */
+ int num_addr; /* number of addresses to try to connect to */
+ long timeoutms_per_addr; /* how long time in milliseconds to spend on
+ trying to connect to each IP address */
+
+ const struct Curl_handler *handler; /* Connection's protocol handler */
+ const struct Curl_handler *given; /* The protocol first given */
+
+ long ip_version; /* copied from the SessionHandle at creation time */
+
+ /**** curl_get() phase fields */
+
+ curl_socket_t sockfd; /* socket to read from or CURL_SOCKET_BAD */
+ curl_socket_t writesockfd; /* socket to write to, it may very
+ well be the same we read from.
+ CURL_SOCKET_BAD disables */
+
+ /** Dynamicly allocated strings, MUST be freed before this **/
+ /** struct is killed. **/
+ struct dynamically_allocated_data {
+ char *proxyuserpwd;
+ char *uagent;
+ char *accept_encoding;
+ char *userpwd;
+ char *rangeline;
+ char *ref;
+ char *host;
+ char *cookiehost;
+ char *rtsp_transport;
+ char *te; /* TE: request header */
+ } allocptr;
+
+ int sec_complete; /* if kerberos is enabled for this connection */
+#ifdef HAVE_GSSAPI
+ enum protection_level command_prot;
+ enum protection_level data_prot;
+ enum protection_level request_data_prot;
+ size_t buffer_size;
+ struct krb5buffer in_buffer;
+ void *app_data;
+ const struct Curl_sec_client_mech *mech;
+ struct sockaddr_in local_addr;
+#endif
+
+ /* the two following *_inuse fields are only flags, not counters in any way.
+ If TRUE it means the channel is in use, and if FALSE it means the channel
+ is up for grabs by one. */
+
+ bool readchannel_inuse; /* whether the read channel is in use by an easy
+ handle */
+ bool writechannel_inuse; /* whether the write channel is in use by an easy
+ handle */
+ struct curl_llist *send_pipe; /* List of handles waiting to
+ send on this pipeline */
+ struct curl_llist *recv_pipe; /* List of handles waiting to read
+ their responses on this pipeline */
+ char* master_buffer; /* The master buffer allocated on-demand;
+ used for pipelining. */
+ size_t read_pos; /* Current read position in the master buffer */
+ size_t buf_len; /* Length of the buffer?? */
+
+
+ curl_seek_callback seek_func; /* function that seeks the input */
+ void *seek_client; /* pointer to pass to the seek() above */
+
+ /*************** Request - specific items ************/
+
+ /* previously this was in the urldata struct */
+ curl_read_callback fread_func; /* function that reads the input */
+ void *fread_in; /* pointer to pass to the fread() above */
+
+ struct ntlmdata ntlm; /* NTLM differs from other authentication schemes
+ because it authenticates connections, not
+ single requests! */
+ struct ntlmdata proxyntlm; /* NTLM data for proxy */
+
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ /* used for communication with Samba's winbind daemon helper ntlm_auth */
+ curl_socket_t ntlm_auth_hlpr_socket;
+ pid_t ntlm_auth_hlpr_pid;
+ char* challenge_header;
+ char* response_header;
+#endif
+
+ char syserr_buf [256]; /* buffer for Curl_strerror() */
+
+#ifdef CURLRES_ASYNCH
+ /* data used for the asynch name resolve callback */
+ struct Curl_async async;
+#endif
+
+ /* These three are used for chunked-encoding trailer support */
+ char *trailer; /* allocated buffer to store trailer in */
+ int trlMax; /* allocated buffer size */
+ int trlPos; /* index of where to store data */
+
+ union {
+ struct ftp_conn ftpc;
+ struct http_conn httpc;
+ struct ssh_conn sshc;
+ struct tftp_state_data *tftpc;
+ struct imap_conn imapc;
+ struct pop3_conn pop3c;
+ struct smtp_conn smtpc;
+ struct rtsp_conn rtspc;
+ void *generic; /* RTMP and LDAP use this */
+ } proto;
+
+ int cselect_bits; /* bitmask of socket events */
+ int waitfor; /* current READ/WRITE bits to wait for */
+
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ int socks5_gssapi_enctype;
+#endif
+
+ bool verifypeer;
+ bool verifyhost;
+
+ /* When this connection is created, store the conditions for the local end
+ bind. This is stored before the actual bind and before any connection is
+ made and will serve the purpose of being used for comparison reasons so
+ that subsequent bound-requested connections aren't accidentally re-using
+ wrong connections. */
+ char *localdev;
+ unsigned short localport;
+ int localportrange;
+
+ /* tunnel as in tunnel through a HTTP proxy with CONNECT */
+ enum {
+ TUNNEL_INIT, /* init/default/no tunnel state */
+ TUNNEL_CONNECT, /* CONNECT has been sent off */
+ TUNNEL_COMPLETE /* CONNECT response received completely */
+ } tunnel_state[2]; /* two separate ones to allow FTP */
+ struct connectbundle *bundle; /* The bundle we are member of */
+};
+
+/* The end of connectdata. */
+
+/*
+ * Struct to keep statistical and informational data.
+ */
+struct PureInfo {
+ int httpcode; /* Recent HTTP, FTP, or RTSP response code */
+ int httpproxycode; /* response code from proxy when received separate */
+ int httpversion; /* the http version number X.Y = X*10+Y */
+ long filetime; /* If requested, this is might get set. Set to -1 if the time
+ was unretrievable. We cannot have this of type time_t,
+ since time_t is unsigned on several platforms such as
+ OpenVMS. */
+ bool timecond; /* set to TRUE if the time condition didn't match, which
+ thus made the document NOT get fetched */
+ long header_size; /* size of read header(s) in bytes */
+ long request_size; /* the amount of bytes sent in the request(s) */
+ unsigned long proxyauthavail; /* what proxy auth types were announced */
+ unsigned long httpauthavail; /* what host auth types were announced */
+ long numconnects; /* how many new connection did libcurl created */
+ char *contenttype; /* the content type of the object */
+ char *wouldredirect; /* URL this would've been redirected to if asked to */
+
+ /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
+ and, 'conn_local_port' are copied over from the connectdata struct in
+ order to allow curl_easy_getinfo() to return this information even when
+ the session handle is no longer associated with a connection, and also
+ allow curl_easy_reset() to clear this information from the session handle
+ without disturbing information which is still alive, and that might be
+ reused, in the connection cache. */
+
+ char conn_primary_ip[MAX_IPADR_LEN];
+ long conn_primary_port;
+
+ char conn_local_ip[MAX_IPADR_LEN];
+ long conn_local_port;
+
+ struct curl_certinfo certs; /* info about the certs, only populated in
+ OpenSSL builds. Asked for with
+ CURLOPT_CERTINFO / CURLINFO_CERTINFO */
+};
+
+
+struct Progress {
+ long lastshow; /* time() of the last displayed progress meter or NULL to
+ force redraw at next call */
+ curl_off_t size_dl; /* total expected size */
+ curl_off_t size_ul; /* total expected size */
+ curl_off_t downloaded; /* transferred so far */
+ curl_off_t uploaded; /* transferred so far */
+
+ curl_off_t current_speed; /* uses the currently fastest transfer */
+
+ bool callback; /* set when progress callback is used */
+ int width; /* screen width at download start */
+ int flags; /* see progress.h */
+
+ double timespent;
+
+ curl_off_t dlspeed;
+ curl_off_t ulspeed;
+
+ double t_nslookup;
+ double t_connect;
+ double t_appconnect;
+ double t_pretransfer;
+ double t_starttransfer;
+ double t_redirect;
+
+ struct timeval start;
+ struct timeval t_startsingle;
+ struct timeval t_acceptdata;
+#define CURR_TIME (5+1) /* 6 entries for 5 seconds */
+
+ curl_off_t speeder[ CURR_TIME ];
+ struct timeval speeder_time[ CURR_TIME ];
+ int speeder_c;
+};
+
+typedef enum {
+ HTTPREQ_NONE, /* first in list */
+ HTTPREQ_GET,
+ HTTPREQ_POST,
+ HTTPREQ_POST_FORM, /* we make a difference internally */
+ HTTPREQ_PUT,
+ HTTPREQ_HEAD,
+ HTTPREQ_CUSTOM,
+ HTTPREQ_LAST /* last in list */
+} Curl_HttpReq;
+
+typedef enum {
+ RTSPREQ_NONE, /* first in list */
+ RTSPREQ_OPTIONS,
+ RTSPREQ_DESCRIBE,
+ RTSPREQ_ANNOUNCE,
+ RTSPREQ_SETUP,
+ RTSPREQ_PLAY,
+ RTSPREQ_PAUSE,
+ RTSPREQ_TEARDOWN,
+ RTSPREQ_GET_PARAMETER,
+ RTSPREQ_SET_PARAMETER,
+ RTSPREQ_RECORD,
+ RTSPREQ_RECEIVE,
+ RTSPREQ_LAST /* last in list */
+} Curl_RtspReq;
+
+/*
+ * Values that are generated, temporary or calculated internally for a
+ * "session handle" must be defined within the 'struct UrlState'. This struct
+ * will be used within the SessionHandle struct. When the 'SessionHandle'
+ * struct is cloned, this data MUST NOT be copied.
+ *
+ * Remember that any "state" information goes globally for the curl handle.
+ * Session-data MUST be put in the connectdata struct and here. */
+#define MAX_CURL_USER_LENGTH 256
+#define MAX_CURL_PASSWORD_LENGTH 256
+
+struct auth {
+ unsigned long want; /* Bitmask set to the authentication methods wanted by
+ app (with CURLOPT_HTTPAUTH or CURLOPT_PROXYAUTH). */
+ unsigned long picked;
+ unsigned long avail; /* Bitmask for what the server reports to support for
+ this resource */
+ bool done; /* TRUE when the auth phase is done and ready to do the *actual*
+ request */
+ bool multi; /* TRUE if this is not yet authenticated but within the auth
+ multipass negotiation */
+ bool iestyle; /* TRUE if digest should be done IE-style or FALSE if it should
+ be RFC compliant */
+};
+
+struct UrlState {
+
+ /* Points to the connection cache */
+ struct conncache *conn_cache;
+
+ /* when curl_easy_perform() is called, the multi handle is "owned" by
+ the easy handle so curl_easy_cleanup() on such an easy handle will
+ also close the multi handle! */
+ bool multi_owned_by_easy;
+
+ /* buffers to store authentication data in, as parsed from input options */
+ struct timeval keeps_speed; /* for the progress meter really */
+
+ struct connectdata *lastconnect; /* The last connection, NULL if undefined */
+
+ char *headerbuff; /* allocated buffer to store headers in */
+ size_t headersize; /* size of the allocation */
+
+ char buffer[BUFSIZE+1]; /* download buffer */
+ char uploadbuffer[BUFSIZE+1]; /* upload buffer */
+ curl_off_t current_speed; /* the ProgressShow() funcion sets this,
+ bytes / second */
+ bool this_is_a_follow; /* this is a followed Location: request */
+
+ char *first_host; /* if set, this should be the host name that we will
+ sent authorization to, no else. Used to make Location:
+ following not keep sending user+password... This is
+ strdup() data.
+ */
+ struct curl_ssl_session *session; /* array of 'max_ssl_sessions' size */
+ long sessionage; /* number of the most recent session */
+ char *tempwrite; /* allocated buffer to keep data in when a write
+ callback returns to make the connection paused */
+ size_t tempwritesize; /* size of the 'tempwrite' allocated buffer */
+ int tempwritetype; /* type of the 'tempwrite' buffer as a bitmask that is
+ used with Curl_client_write() */
+ char *scratch; /* huge buffer[BUFSIZE*2] when doing upload CRLF replacing */
+ bool errorbuf; /* Set to TRUE if the error buffer is already filled in.
+ This must be set to FALSE every time _easy_perform() is
+ called. */
+ int os_errno; /* filled in with errno whenever an error occurs */
+#ifdef HAVE_SIGNAL
+ /* storage for the previous bag^H^H^HSIGPIPE signal handler :-) */
+ void (*prev_signal)(int sig);
+#endif
+ bool allow_port; /* Is set.use_port allowed to take effect or not. This
+ is always set TRUE when curl_easy_perform() is called. */
+ struct digestdata digest; /* state data for host Digest auth */
+ struct digestdata proxydigest; /* state data for proxy Digest auth */
+
+#ifdef USE_HTTP_NEGOTIATE
+ struct negotiatedata negotiate; /* state data for host Negotiate auth */
+ struct negotiatedata proxyneg; /* state data for proxy Negotiate auth */
+#endif
+
+ struct auth authhost; /* auth details for host */
+ struct auth authproxy; /* auth details for proxy */
+
+ bool authproblem; /* TRUE if there's some problem authenticating */
+
+ void *resolver; /* resolver state, if it is used in the URL state -
+ ares_channel f.e. */
+
+#if defined(USE_SSLEAY) && defined(HAVE_OPENSSL_ENGINE_H)
+ ENGINE *engine;
+#endif /* USE_SSLEAY */
+ struct timeval expiretime; /* set this with Curl_expire() only */
+ struct Curl_tree timenode; /* for the splay stuff */
+ struct curl_llist *timeoutlist; /* list of pending timeouts */
+
+ /* a place to store the most recently set FTP entrypath */
+ char *most_recent_ftp_entrypath;
+
+ /* set after initial USER failure, to prevent an authentication loop */
+ bool ftp_trying_alternative;
+
+ int httpversion; /* the lowest HTTP version*10 reported by any server
+ involved in this request */
+ bool expect100header; /* TRUE if we added Expect: 100-continue */
+
+ bool pipe_broke; /* TRUE if the connection we were pipelined on broke
+ and we need to restart from the beginning */
+
+#if !defined(WIN32) && !defined(MSDOS) && !defined(__EMX__) && \
+ !defined(__SYMBIAN32__)
+/* do FTP line-end conversions on most platforms */
+#define CURL_DO_LINEEND_CONV
+ /* for FTP downloads: track CRLF sequences that span blocks */
+ bool prev_block_had_trailing_cr;
+ /* for FTP downloads: how many CRLFs did we converted to LFs? */
+ curl_off_t crlf_conversions;
+#endif
+ char *pathbuffer;/* allocated buffer to store the URL's path part in */
+ char *path; /* path to use, points to somewhere within the pathbuffer
+ area */
+ bool slash_removed; /* set TRUE if the 'path' points to a path where the
+ initial URL slash separator has been taken off */
+ bool use_range;
+ bool rangestringalloc; /* the range string is malloc()'ed */
+
+ char *range; /* range, if used. See README for detailed specification on
+ this syntax. */
+ curl_off_t resume_from; /* continue [ftp] transfer from here */
+
+ /* This RTSP state information survives requests and connections */
+ long rtsp_next_client_CSeq; /* the session's next client CSeq */
+ long rtsp_next_server_CSeq; /* the session's next server CSeq */
+ long rtsp_CSeq_recv; /* most recent CSeq received */
+
+ /* if true, force SSL connection retry (workaround for certain servers) */
+ bool ssl_connect_retry;
+};
+
+
+/*
+ * This 'DynamicStatic' struct defines dynamic states that actually change
+ * values in the 'UserDefined' area, which MUST be taken into consideration
+ * if the UserDefined struct is cloned or similar. You can probably just
+ * copy these, but each one indicate a special action on other data.
+ */
+
+struct DynamicStatic {
+ char *url; /* work URL, copied from UserDefined */
+ bool url_alloc; /* URL string is malloc()'ed */
+ char *referer; /* referer string */
+ bool referer_alloc; /* referer sting is malloc()ed */
+ struct curl_slist *cookielist; /* list of cookie files set by
+ curl_easy_setopt(COOKIEFILE) calls */
+ struct curl_slist *resolve; /* set to point to the set.resolve list when
+ this should be dealt with in pretransfer */
+};
+
+/*
+ * This 'UserDefined' struct must only contain data that is set once to go
+ * for many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" MUST be defined within the
+ * 'struct UrlState' instead. The only exceptions MUST note the changes in
+ * the 'DynamicStatic' struct.
+ * Character pointer fields point to dynamic storage, unless otherwise stated.
+ */
+
+struct Curl_multi; /* declared and used only in multi.c */
+
+enum dupstring {
+ STRING_CERT, /* client certificate file name */
+ STRING_CERT_TYPE, /* format for certificate (default: PEM)*/
+ STRING_COOKIE, /* HTTP cookie string to send */
+ STRING_COOKIEJAR, /* dump all cookies to this file */
+ STRING_CUSTOMREQUEST, /* HTTP/FTP/RTSP request/method to use */
+ STRING_DEVICE, /* local network interface/address to use */
+ STRING_ENCODING, /* Accept-Encoding string */
+ STRING_FTP_ACCOUNT, /* ftp account data */
+ STRING_FTP_ALTERNATIVE_TO_USER, /* command to send if USER/PASS fails */
+ STRING_FTPPORT, /* port to send with the FTP PORT command */
+ STRING_KEY, /* private key file name */
+ STRING_KEY_PASSWD, /* plain text private key password */
+ STRING_KEY_TYPE, /* format for private key (default: PEM) */
+ STRING_KRB_LEVEL, /* krb security level */
+ STRING_NETRC_FILE, /* if not NULL, use this instead of trying to find
+ $HOME/.netrc */
+ STRING_COPYPOSTFIELDS, /* if POST, set the fields' values here */
+ STRING_PROXY, /* proxy to use */
+ STRING_SET_RANGE, /* range, if used */
+ STRING_SET_REFERER, /* custom string for the HTTP referer field */
+ STRING_SET_URL, /* what original URL to work on */
+ STRING_SSL_CAPATH, /* CA directory name (doesn't work on windows) */
+ STRING_SSL_CAFILE, /* certificate file to verify peer against */
+ STRING_SSL_CIPHER_LIST, /* list of ciphers to use */
+ STRING_SSL_EGDSOCKET, /* path to file containing the EGD daemon socket */
+ STRING_SSL_RANDOM_FILE, /* path to file containing "random" data */
+ STRING_USERAGENT, /* User-Agent string */
+ STRING_SSL_CRLFILE, /* crl file to check certificate */
+ STRING_SSL_ISSUERCERT, /* issuer cert file to check certificate */
+ STRING_USERNAME, /* <username>, if used */
+ STRING_PASSWORD, /* <password>, if used */
+ STRING_OPTIONS, /* <options>, if used */
+ STRING_PROXYUSERNAME, /* Proxy <username>, if used */
+ STRING_PROXYPASSWORD, /* Proxy <password>, if used */
+ STRING_NOPROXY, /* List of hosts which should not use the proxy, if
+ used */
+ STRING_RTSP_SESSION_ID, /* Session ID to use */
+ STRING_RTSP_STREAM_URI, /* Stream URI for this request */
+ STRING_RTSP_TRANSPORT, /* Transport for this session */
+#ifdef USE_LIBSSH2
+ STRING_SSH_PRIVATE_KEY, /* path to the private key file for auth */
+ STRING_SSH_PUBLIC_KEY, /* path to the public key file for auth */
+ STRING_SSH_HOST_PUBLIC_KEY_MD5, /* md5 of host public key in ascii hex */
+ STRING_SSH_KNOWNHOSTS, /* file name of knownhosts file */
+#endif
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ STRING_SOCKS5_GSSAPI_SERVICE, /* GSSAPI service name */
+#endif
+ STRING_MAIL_FROM,
+ STRING_MAIL_AUTH,
+
+#ifdef USE_TLS_SRP
+ STRING_TLSAUTH_USERNAME, /* TLS auth <username> */
+ STRING_TLSAUTH_PASSWORD, /* TLS auth <password> */
+#endif
+
+ STRING_BEARER, /* <bearer>, if used */
+
+ /* -- end of strings -- */
+ STRING_LAST /* not used, just an end-of-list marker */
+};
+
+struct UserDefined {
+ FILE *err; /* the stderr user data goes here */
+ void *debugdata; /* the data that will be passed to fdebug */
+ char *errorbuffer; /* (Static) store failure messages in here */
+ long proxyport; /* If non-zero, use this port number by default. If the
+ proxy string features a ":[port]" that one will override
+ this. */
+ void *out; /* the fetched file goes here */
+ void *in; /* the uploaded file is read from here */
+ void *writeheader; /* write the header to this if non-NULL */
+ void *rtp_out; /* write RTP to this if non-NULL */
+ long use_port; /* which port to use (when not using default) */
+ unsigned long httpauth; /* kind of HTTP authentication to use (bitmask) */
+ unsigned long proxyauth; /* kind of proxy authentication to use (bitmask) */
+ long followlocation; /* as in HTTP Location: */
+ long maxredirs; /* maximum no. of http(s) redirects to follow, set to -1
+ for infinity */
+
+ int keep_post; /* keep POSTs as POSTs after a 30x request; each
+ bit represents a request, from 301 to 303 */
+ bool free_referer; /* set TRUE if 'referer' points to a string we
+ allocated */
+ void *postfields; /* if POST, set the fields' values here */
+ curl_seek_callback seek_func; /* function that seeks the input */
+ curl_off_t postfieldsize; /* if POST, this might have a size to use instead
+ of strlen(), and then the data *may* be binary
+ (contain zero bytes) */
+ unsigned short localport; /* local port number to bind to */
+ int localportrange; /* number of additional port numbers to test in case the
+ 'localport' one can't be bind()ed */
+ curl_write_callback fwrite_func; /* function that stores the output */
+ curl_write_callback fwrite_header; /* function that stores headers */
+ curl_write_callback fwrite_rtp; /* function that stores interleaved RTP */
+ curl_read_callback fread_func; /* function that reads the input */
+ int is_fread_set; /* boolean, has read callback been set to non-NULL? */
+ int is_fwrite_set; /* boolean, has write callback been set to non-NULL? */
+ curl_progress_callback fprogress; /* OLD and deprecated progress callback */
+ curl_xferinfo_callback fxferinfo; /* progress callback */
+ curl_debug_callback fdebug; /* function that write informational data */
+ curl_ioctl_callback ioctl_func; /* function for I/O control */
+ curl_sockopt_callback fsockopt; /* function for setting socket options */
+ void *sockopt_client; /* pointer to pass to the socket options callback */
+ curl_opensocket_callback fopensocket; /* function for checking/translating
+ the address and opening the
+ socket */
+ void* opensocket_client;
+ curl_closesocket_callback fclosesocket; /* function for closing the
+ socket */
+ void* closesocket_client;
+
+ void *seek_client; /* pointer to pass to the seek callback */
+ /* the 3 curl_conv_callback functions below are used on non-ASCII hosts */
+ /* function to convert from the network encoding: */
+ curl_conv_callback convfromnetwork;
+ /* function to convert to the network encoding: */
+ curl_conv_callback convtonetwork;
+ /* function to convert from UTF-8 encoding: */
+ curl_conv_callback convfromutf8;
+
+ void *progress_client; /* pointer to pass to the progress callback */
+ void *ioctl_client; /* pointer to pass to the ioctl callback */
+ long timeout; /* in milliseconds, 0 means no timeout */
+ long connecttimeout; /* in milliseconds, 0 means no timeout */
+ long accepttimeout; /* in milliseconds, 0 means no timeout */
+ long server_response_timeout; /* in milliseconds, 0 means no timeout */
+ long tftp_blksize ; /* in bytes, 0 means use default */
+ curl_off_t infilesize; /* size of file to upload, -1 means unknown */
+ long low_speed_limit; /* bytes/second */
+ long low_speed_time; /* number of seconds */
+ curl_off_t max_send_speed; /* high speed limit in bytes/second for upload */
+ curl_off_t max_recv_speed; /* high speed limit in bytes/second for
+ download */
+ curl_off_t set_resume_from; /* continue [ftp] transfer from here */
+ struct curl_slist *headers; /* linked list of extra headers */
+ struct curl_httppost *httppost; /* linked list of POST data */
+ bool cookiesession; /* new cookie session? */
+ bool crlf; /* convert crlf on ftp upload(?) */
+ struct curl_slist *quote; /* after connection is established */
+ struct curl_slist *postquote; /* after the transfer */
+ struct curl_slist *prequote; /* before the transfer, after type */
+ struct curl_slist *source_quote; /* 3rd party quote */
+ struct curl_slist *source_prequote; /* in 3rd party transfer mode - before
+ the transfer on source host */
+ struct curl_slist *source_postquote; /* in 3rd party transfer mode - after
+ the transfer on source host */
+ struct curl_slist *telnet_options; /* linked list of telnet options */
+ struct curl_slist *resolve; /* list of names to add/remove from
+ DNS cache */
+ curl_TimeCond timecondition; /* kind of time/date comparison */
+ time_t timevalue; /* what time to compare with */
+ Curl_HttpReq httpreq; /* what kind of HTTP request (if any) is this */
+ long httpversion; /* when non-zero, a specific HTTP version requested to
+ be used in the library's request(s) */
+ struct ssl_config_data ssl; /* user defined SSL stuff */
+ curl_proxytype proxytype; /* what kind of proxy that is in use */
+ long dns_cache_timeout; /* DNS cache timeout */
+ long buffer_size; /* size of receive buffer to use */
+ void *private_data; /* application-private data */
+
+ struct curl_slist *http200aliases; /* linked list of aliases for http200 */
+
+ long ipver; /* the CURL_IPRESOLVE_* defines in the public header file
+ 0 - whatever, 1 - v2, 2 - v6 */
+
+ curl_off_t max_filesize; /* Maximum file size to download */
+
+ curl_ftpfile ftp_filemethod; /* how to get to a file when FTP is used */
+
+ int ftp_create_missing_dirs; /* 1 - create directories that don't exist
+ 2 - the same but also allow MKD to fail once
+ */
+
+ curl_sshkeycallback ssh_keyfunc; /* key matching callback */
+ void *ssh_keyfunc_userp; /* custom pointer to callback */
+
+/* Here follows boolean settings that define how to behave during
+ this session. They are STATIC, set by libcurl users or at least initially
+ and they don't change during operations. */
+
+ bool printhost; /* printing host name in debug info */
+ bool get_filetime; /* get the time and get of the remote file */
+ bool tunnel_thru_httpproxy; /* use CONNECT through a HTTP proxy */
+ bool prefer_ascii; /* ASCII rather than binary */
+ bool ftp_append; /* append, not overwrite, on upload */
+ bool ftp_list_only; /* switch FTP command for listing directories */
+ bool ftp_use_port; /* use the FTP PORT command */
+ bool hide_progress; /* don't use the progress meter */
+ bool http_fail_on_error; /* fail on HTTP error codes >= 300 */
+ bool http_follow_location; /* follow HTTP redirects */
+ bool http_transfer_encoding; /* request compressed HTTP transfer-encoding */
+ bool http_disable_hostname_check_before_authentication;
+ bool include_header; /* include received protocol headers in data output */
+ bool http_set_referer; /* is a custom referer used */
+ bool http_auto_referer; /* set "correct" referer when following location: */
+ bool opt_no_body; /* as set with CURLOPT_NOBODY */
+ bool set_port; /* custom port number used */
+ bool upload; /* upload request */
+ enum CURL_NETRC_OPTION
+ use_netrc; /* defined in include/curl.h */
+ bool verbose; /* output verbosity */
+ bool krb; /* kerberos connection requested */
+ bool reuse_forbid; /* forbidden to be reused, close after use */
+ bool reuse_fresh; /* do not re-use an existing connection */
+ bool ftp_use_epsv; /* if EPSV is to be attempted or not */
+ bool ftp_use_eprt; /* if EPRT is to be attempted or not */
+ bool ftp_use_pret; /* if PRET is to be used before PASV or not */
+
+ curl_usessl use_ssl; /* if AUTH TLS is to be attempted etc, for FTP or
+ IMAP or POP3 or others! */
+ curl_ftpauth ftpsslauth; /* what AUTH XXX to be attempted */
+ curl_ftpccc ftp_ccc; /* FTP CCC options */
+ bool no_signal; /* do not use any signal/alarm handler */
+ bool global_dns_cache; /* subject for future removal */
+ bool tcp_nodelay; /* whether to enable TCP_NODELAY or not */
+ bool ignorecl; /* ignore content length */
+ bool ftp_skip_ip; /* skip the IP address the FTP server passes on to
+ us */
+ bool connect_only; /* make connection, let application use the socket */
+ bool ssl_enable_beast; /* especially allow this flaw for interoperability's
+ sake*/
+ long ssh_auth_types; /* allowed SSH auth types */
+ bool http_te_skip; /* pass the raw body data to the user, even when
+ transfer-encoded (chunked, compressed) */
+ bool http_ce_skip; /* pass the raw body data to the user, even when
+ content-encoded (chunked, compressed) */
+ long new_file_perms; /* Permissions to use when creating remote files */
+ long new_directory_perms; /* Permissions to use when creating remote dirs */
+ bool proxy_transfer_mode; /* set transfer mode (;type=<a|i>) when doing FTP
+ via an HTTP proxy */
+ char *str[STRING_LAST]; /* array of strings, pointing to allocated memory */
+ unsigned int scope; /* address scope for IPv6 */
+ long allowed_protocols;
+ long redir_protocols;
+#if defined(HAVE_GSSAPI) || defined(USE_WINDOWS_SSPI)
+ long socks5_gssapi_nec; /* flag to support nec socks5 server */
+#endif
+ struct curl_slist *mail_rcpt; /* linked list of mail recipients */
+ bool sasl_ir; /* Enable/disable SASL initial response */
+ /* Common RTSP header options */
+ Curl_RtspReq rtspreq; /* RTSP request type */
+ long rtspversion; /* like httpversion, for RTSP */
+ bool wildcardmatch; /* enable wildcard matching */
+ curl_chunk_bgn_callback chunk_bgn; /* called before part of transfer
+ starts */
+ curl_chunk_end_callback chunk_end; /* called after part transferring
+ stopped */
+ curl_fnmatch_callback fnmatch; /* callback to decide which file corresponds
+ to pattern (e.g. if WILDCARDMATCH is on) */
+ void *fnmatch_data;
+
+ long gssapi_delegation; /* GSSAPI credential delegation, see the
+ documentation of CURLOPT_GSSAPI_DELEGATION */
+
+ bool tcp_keepalive; /* use TCP keepalives */
+ long tcp_keepidle; /* seconds in idle before sending keepalive probe */
+ long tcp_keepintvl; /* seconds between TCP keepalive probes */
+
+ size_t maxconnects; /* Max idle connections in the connection cache */
+};
+
+struct Names {
+ struct curl_hash *hostcache;
+ enum {
+ HCACHE_NONE, /* not pointing to anything */
+ HCACHE_GLOBAL, /* points to the (shrug) global one */
+ HCACHE_MULTI, /* points to a shared one in the multi handle */
+ HCACHE_SHARED /* points to a shared one in a shared object */
+ } hostcachetype;
+};
+
+/*
+ * The 'connectdata' struct MUST have all the connection oriented stuff as we
+ * may have several simultaneous connections and connection structs in memory.
+ *
+ * The 'struct UserDefined' must only contain data that is set once to go for
+ * many (perhaps) independent connections. Values that are generated or
+ * calculated internally for the "session handle" must be defined within the
+ * 'struct UrlState' instead.
+ */
+
+struct SessionHandle {
+ /* first, two fields for the linked list of these */
+ struct SessionHandle *next;
+ struct SessionHandle *prev;
+
+ struct connectdata *easy_conn; /* the "unit's" connection */
+
+ CURLMstate mstate; /* the handle's state */
+ CURLcode result; /* previous result */
+
+ struct Curl_message msg; /* A single posted message. */
+
+ /* Array with the plain socket numbers this handle takes care of, in no
+ particular order. Note that all sockets are added to the sockhash, where
+ the state etc are also kept. This array is mostly used to detect when a
+ socket is to be removed from the hash. See singlesocket(). */
+ curl_socket_t sockets[MAX_SOCKSPEREASYHANDLE];
+ int numsocks;
+
+ struct Names dns;
+ struct Curl_multi *multi; /* if non-NULL, points to the multi handle
+ struct to which this "belongs" when used by
+ the multi interface */
+ struct Curl_multi *multi_easy; /* if non-NULL, points to the multi handle
+ struct to which this "belongs" when used
+ by the easy interface */
+ struct Curl_share *share; /* Share, handles global variable mutexing */
+ struct SingleRequest req; /* Request-specific data */
+ struct UserDefined set; /* values set by the libcurl user */
+ struct DynamicStatic change; /* possibly modified userdefined data */
+ struct CookieInfo *cookies; /* the cookies, read from files and servers.
+ NOTE that the 'cookie' field in the
+ UserDefined struct defines if the "engine"
+ is to be used or not. */
+ struct Progress progress; /* for all the progress meter data */
+ struct UrlState state; /* struct for fields used for state info and
+ other dynamic purposes */
+ struct WildcardData wildcard; /* wildcard download state info */
+ struct PureInfo info; /* stats, reports and info data */
+#if defined(CURL_DOES_CONVERSIONS) && defined(HAVE_ICONV)
+ iconv_t outbound_cd; /* for translating to the network encoding */
+ iconv_t inbound_cd; /* for translating from the network encoding */
+ iconv_t utf8_cd; /* for translating to UTF8 */
+#endif /* CURL_DOES_CONVERSIONS && HAVE_ICONV */
+ unsigned int magic; /* set to a CURLEASY_MAGIC_NUMBER */
+};
+
+#define LIBCURL_NAME "libcurl"
+
+#endif /* HEADER_CURL_URLDATA_H */
diff --git a/libs/libcurl/src/version.c b/libs/libcurl/src/version.c
new file mode 100644
index 0000000000..1f62131eba
--- /dev/null
+++ b/libs/libcurl/src/version.c
@@ -0,0 +1,349 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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 <curl/curl.h>
+#include "urldata.h"
+#include "sslgen.h"
+#include "http2.h"
+
+#define _MPRINTF_REPLACE /* use the internal *printf() functions */
+#include <curl/mprintf.h>
+
+#ifdef USE_ARES
+# if defined(CURL_STATICLIB) && !defined(CARES_STATICLIB) && \
+ (defined(WIN32) || defined(_WIN32) || defined(__SYMBIAN32__))
+# define CARES_STATICLIB
+# endif
+# include <ares.h>
+#endif
+
+#ifdef USE_LIBIDN
+#include <stringprep.h>
+#endif
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#include <iconv.h>
+#endif
+
+#ifdef USE_LIBRTMP
+#include <librtmp/rtmp.h>
+#endif
+
+#ifdef USE_LIBSSH2
+#include <libssh2.h>
+#endif
+
+#ifdef HAVE_LIBSSH2_VERSION
+/* get it run-time if possible */
+#define CURL_LIBSSH2_VERSION libssh2_version(0)
+#else
+/* use build-time if run-time not possible */
+#define CURL_LIBSSH2_VERSION LIBSSH2_VERSION
+#endif
+
+char *curl_version(void)
+{
+ static char version[200];
+ char *ptr = version;
+ size_t len;
+ size_t left = sizeof(version);
+
+ strcpy(ptr, LIBCURL_NAME "/" LIBCURL_VERSION);
+ len = strlen(ptr);
+ left -= len;
+ ptr += len;
+
+ if(left > 1) {
+ len = Curl_ssl_version(ptr + 1, left - 1);
+
+ if(len > 0) {
+ *ptr = ' ';
+ left -= ++len;
+ ptr += len;
+ }
+ }
+
+#ifdef HAVE_LIBZ
+ len = snprintf(ptr, left, " zlib/%s", zlibVersion());
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_ARES
+ /* this function is only present in c-ares, not in the original ares */
+ len = snprintf(ptr, left, " c-ares/%s", ares_version(NULL));
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBIDN
+ if(stringprep_check_version(LIBIDN_REQUIRED_VERSION)) {
+ len = snprintf(ptr, left, " libidn/%s", stringprep_check_version(NULL));
+ left -= len;
+ ptr += len;
+ }
+#endif
+#ifdef USE_WIN32_IDN
+ len = snprintf(ptr, left, " WinIDN");
+ left -= len;
+ ptr += len;
+#endif
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+ len = snprintf(ptr, left, " iconv/%d.%d",
+ _LIBICONV_VERSION >> 8, _LIBICONV_VERSION & 255);
+#else
+ /* version unknown */
+ len = snprintf(ptr, left, " iconv");
+#endif /* _LIBICONV_VERSION */
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBSSH2
+ len = snprintf(ptr, left, " libssh2/%s", CURL_LIBSSH2_VERSION);
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_NGHTTP2
+ len = Curl_http2_ver(ptr, left);
+ left -= len;
+ ptr += len;
+#endif
+#ifdef USE_LIBRTMP
+ {
+ char suff[2];
+ if(RTMP_LIB_VERSION & 0xff) {
+ suff[0] = (RTMP_LIB_VERSION & 0xff) + 'a' - 1;
+ suff[1] = '\0';
+ }
+ else
+ suff[0] = '\0';
+
+ snprintf(ptr, left, " librtmp/%d.%d%s",
+ RTMP_LIB_VERSION >> 16, (RTMP_LIB_VERSION >> 8) & 0xff,
+ suff);
+/*
+ If another lib version is added below this one, this code would
+ also have to do:
+
+ len = what snprintf() returned
+
+ left -= len;
+ ptr += len;
+*/
+ }
+#endif
+
+ return version;
+}
+
+/* data for curl_version_info
+
+ Keep the list sorted alphabetically. It is also written so that each
+ protocol line has its own #if line to make things easier on the eye.
+ */
+
+static const char * const protocols[] = {
+#ifndef CURL_DISABLE_DICT
+ "dict",
+#endif
+#ifndef CURL_DISABLE_FILE
+ "file",
+#endif
+#ifndef CURL_DISABLE_FTP
+ "ftp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_FTP)
+ "ftps",
+#endif
+#ifndef CURL_DISABLE_GOPHER
+ "gopher",
+#endif
+#ifndef CURL_DISABLE_HTTP
+ "http",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_HTTP)
+ "https",
+#endif
+#ifndef CURL_DISABLE_IMAP
+ "imap",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_IMAP)
+ "imaps",
+#endif
+#ifndef CURL_DISABLE_LDAP
+ "ldap",
+#if !defined(CURL_DISABLE_LDAPS) && \
+ ((defined(USE_OPENLDAP) && defined(USE_SSL)) || \
+ (!defined(USE_OPENLDAP) && defined(HAVE_LDAP_SSL)))
+ "ldaps",
+#endif
+#endif
+#ifndef CURL_DISABLE_POP3
+ "pop3",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_POP3)
+ "pop3s",
+#endif
+#ifdef USE_LIBRTMP
+ "rtmp",
+#endif
+#ifndef CURL_DISABLE_RTSP
+ "rtsp",
+#endif
+#ifdef USE_LIBSSH2
+ "scp",
+#endif
+#ifdef USE_LIBSSH2
+ "sftp",
+#endif
+#ifndef CURL_DISABLE_SMTP
+ "smtp",
+#endif
+#if defined(USE_SSL) && !defined(CURL_DISABLE_SMTP)
+ "smtps",
+#endif
+#ifndef CURL_DISABLE_TELNET
+ "telnet",
+#endif
+#ifndef CURL_DISABLE_TFTP
+ "tftp",
+#endif
+
+ NULL
+};
+
+static curl_version_info_data version_info = {
+ CURLVERSION_NOW,
+ LIBCURL_VERSION,
+ LIBCURL_VERSION_NUM,
+ OS, /* as found by configure or set by hand at build-time */
+ 0 /* features is 0 by default */
+#ifdef ENABLE_IPV6
+ | CURL_VERSION_IPV6
+#endif
+#ifdef USE_SSL
+ | CURL_VERSION_SSL
+#endif
+#ifdef USE_NTLM
+ | CURL_VERSION_NTLM
+#endif
+#if defined(USE_NTLM) && defined(NTLM_WB_ENABLED)
+ | CURL_VERSION_NTLM_WB
+#endif
+#ifdef USE_WINDOWS_SSPI
+ | CURL_VERSION_SSPI
+#endif
+#ifdef HAVE_LIBZ
+ | CURL_VERSION_LIBZ
+#endif
+#ifdef USE_HTTP_NEGOTIATE
+ | CURL_VERSION_GSSNEGOTIATE
+#endif
+#ifdef DEBUGBUILD
+ | CURL_VERSION_DEBUG
+#endif
+#ifdef CURLDEBUG
+ | CURL_VERSION_CURLDEBUG
+#endif
+#ifdef CURLRES_ASYNCH
+ | CURL_VERSION_ASYNCHDNS
+#endif
+#ifdef HAVE_SPNEGO
+ | CURL_VERSION_SPNEGO
+#endif
+#if (CURL_SIZEOF_CURL_OFF_T > 4) && \
+ ( (SIZEOF_OFF_T > 4) || defined(USE_WIN32_LARGE_FILES) )
+ | CURL_VERSION_LARGEFILE
+#endif
+#if defined(CURL_DOES_CONVERSIONS)
+ | CURL_VERSION_CONV
+#endif
+#if defined(USE_TLS_SRP)
+ | CURL_VERSION_TLSAUTH_SRP
+#endif
+#if defined(USE_NGHTTP2)
+ | CURL_VERSION_HTTP2
+#endif
+ ,
+ NULL, /* ssl_version */
+ 0, /* ssl_version_num, this is kept at zero */
+ NULL, /* zlib_version */
+ protocols,
+ NULL, /* c-ares version */
+ 0, /* c-ares version numerical */
+ NULL, /* libidn version */
+ 0, /* iconv version */
+ NULL, /* ssh lib version */
+};
+
+curl_version_info_data *curl_version_info(CURLversion stamp)
+{
+#ifdef USE_LIBSSH2
+ static char ssh_buffer[80];
+#endif
+
+#ifdef USE_SSL
+ static char ssl_buffer[80];
+ Curl_ssl_version(ssl_buffer, sizeof(ssl_buffer));
+ version_info.ssl_version = ssl_buffer;
+#endif
+
+#ifdef HAVE_LIBZ
+ version_info.libz_version = zlibVersion();
+ /* libz left NULL if non-existing */
+#endif
+#ifdef USE_ARES
+ {
+ int aresnum;
+ version_info.ares = ares_version(&aresnum);
+ version_info.ares_num = aresnum;
+ }
+#endif
+#ifdef USE_LIBIDN
+ /* This returns a version string if we use the given version or later,
+ otherwise it returns NULL */
+ version_info.libidn = stringprep_check_version(LIBIDN_REQUIRED_VERSION);
+ if(version_info.libidn)
+ version_info.features |= CURL_VERSION_IDN;
+#elif defined(USE_WIN32_IDN)
+ version_info.features |= CURL_VERSION_IDN;
+#endif
+
+#if defined(HAVE_ICONV) && defined(CURL_DOES_CONVERSIONS)
+#ifdef _LIBICONV_VERSION
+ version_info.iconv_ver_num = _LIBICONV_VERSION;
+#else
+ /* version unknown */
+ version_info.iconv_ver_num = -1;
+#endif /* _LIBICONV_VERSION */
+#endif
+
+#ifdef USE_LIBSSH2
+ snprintf(ssh_buffer, sizeof(ssh_buffer), "libssh2/%s", LIBSSH2_VERSION);
+ version_info.libssh_version = ssh_buffer;
+#endif
+
+ (void)stamp; /* avoid compiler warnings, we don't use this */
+
+ return &version_info;
+}
diff --git a/libs/libcurl/src/warnless.c b/libs/libcurl/src/warnless.c
new file mode 100644
index 0000000000..7a4b01eb6d
--- /dev/null
+++ b/libs/libcurl/src/warnless.c
@@ -0,0 +1,453 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+#ifdef HAVE_NETINET_IN_H
+# include <netinet/in.h>
+#endif
+#ifdef HAVE_ARPA_INET_H
+# include <arpa/inet.h>
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#define BUILDING_WARNLESS_C 1
+
+#include "warnless.h"
+
+#define CURL_MASK_SCHAR 0x7F
+#define CURL_MASK_UCHAR 0xFF
+
+#if (SIZEOF_SHORT == 2)
+# define CURL_MASK_SSHORT 0x7FFF
+# define CURL_MASK_USHORT 0xFFFF
+#elif (SIZEOF_SHORT == 4)
+# define CURL_MASK_SSHORT 0x7FFFFFFF
+# define CURL_MASK_USHORT 0xFFFFFFFF
+#elif (SIZEOF_SHORT == 8)
+# define CURL_MASK_SSHORT 0x7FFFFFFFFFFFFFFF
+# define CURL_MASK_USHORT 0xFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_SHORT not defined"
+#endif
+
+#if (SIZEOF_INT == 2)
+# define CURL_MASK_SINT 0x7FFF
+# define CURL_MASK_UINT 0xFFFF
+#elif (SIZEOF_INT == 4)
+# define CURL_MASK_SINT 0x7FFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFF
+#elif (SIZEOF_INT == 8)
+# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFF
+#elif (SIZEOF_INT == 16)
+# define CURL_MASK_SINT 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+# define CURL_MASK_UINT 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF
+#else
+# error "SIZEOF_INT not defined"
+#endif
+
+#if (CURL_SIZEOF_LONG == 2)
+# define CURL_MASK_SLONG 0x7FFFL
+# define CURL_MASK_ULONG 0xFFFFUL
+#elif (CURL_SIZEOF_LONG == 4)
+# define CURL_MASK_SLONG 0x7FFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 8)
+# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFUL
+#elif (CURL_SIZEOF_LONG == 16)
+# define CURL_MASK_SLONG 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFL
+# define CURL_MASK_ULONG 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFUL
+#else
+# error "CURL_SIZEOF_LONG not defined"
+#endif
+
+#if (CURL_SIZEOF_CURL_OFF_T == 2)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 4)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 8)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFF)
+#elif (CURL_SIZEOF_CURL_OFF_T == 16)
+# define CURL_MASK_SCOFFT CURL_OFF_T_C(0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+# define CURL_MASK_UCOFFT CURL_OFF_TU_C(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
+#else
+# error "CURL_SIZEOF_CURL_OFF_T not defined"
+#endif
+
+#if (SIZEOF_SIZE_T == SIZEOF_SHORT)
+# define CURL_MASK_SSIZE_T CURL_MASK_SSHORT
+# define CURL_MASK_USIZE_T CURL_MASK_USHORT
+#elif (SIZEOF_SIZE_T == SIZEOF_INT)
+# define CURL_MASK_SSIZE_T CURL_MASK_SINT
+# define CURL_MASK_USIZE_T CURL_MASK_UINT
+#elif (SIZEOF_SIZE_T == CURL_SIZEOF_LONG)
+# define CURL_MASK_SSIZE_T CURL_MASK_SLONG
+# define CURL_MASK_USIZE_T CURL_MASK_ULONG
+#elif (SIZEOF_SIZE_T == CURL_SIZEOF_CURL_OFF_T)
+# define CURL_MASK_SSIZE_T CURL_MASK_SCOFFT
+# define CURL_MASK_USIZE_T CURL_MASK_UCOFFT
+#else
+# error "SIZEOF_SIZE_T not defined"
+#endif
+
+/*
+** unsigned long to unsigned short
+*/
+
+unsigned short curlx_ultous(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_USHORT);
+ return (unsigned short)(ulnum & (unsigned long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to unsigned char
+*/
+
+unsigned char curlx_ultouc(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_UCHAR);
+ return (unsigned char)(ulnum & (unsigned long) CURL_MASK_UCHAR);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned long to signed int
+*/
+
+int curlx_ultosi(unsigned long ulnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(ulnum <= (unsigned long) CURL_MASK_SINT);
+ return (int)(ulnum & (unsigned long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed int
+*/
+
+int curlx_uztosi(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SINT);
+ return (int)(uznum & (size_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned long
+*/
+
+unsigned long curlx_uztoul(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if (CURL_SIZEOF_LONG < SIZEOF_SIZE_T)
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_ULONG);
+#endif
+ return (unsigned long)(uznum & (size_t) CURL_MASK_ULONG);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to unsigned int
+*/
+
+unsigned int curlx_uztoui(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+#if (SIZEOF_INT < SIZEOF_SIZE_T)
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(uznum & (size_t) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to signed int
+*/
+
+int curlx_sltosi(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_SINT);
+#endif
+ return (int)(slnum & (long) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned int
+*/
+
+unsigned int curlx_sltoui(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+#if (SIZEOF_INT < CURL_SIZEOF_LONG)
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_UINT);
+#endif
+ return (unsigned int)(slnum & (long) CURL_MASK_UINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed long to unsigned short
+*/
+
+unsigned short curlx_sltous(long slnum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(slnum >= 0);
+ DEBUGASSERT((unsigned long) slnum <= (unsigned long) CURL_MASK_USHORT);
+ return (unsigned short)(slnum & (long) CURL_MASK_USHORT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** unsigned size_t to signed ssize_t
+*/
+
+ssize_t curlx_uztosz(size_t uznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(uznum <= (size_t) CURL_MASK_SSIZE_T);
+ return (ssize_t)(uznum & (size_t) CURL_MASK_SSIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed curl_off_t to unsigned size_t
+*/
+
+size_t curlx_sotouz(curl_off_t sonum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sonum >= 0);
+ return (size_t)(sonum & (curl_off_t) CURL_MASK_USIZE_T);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed ssize_t to signed int
+*/
+
+int curlx_sztosi(ssize_t sznum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sznum >= 0);
+#if (SIZEOF_INT < SIZEOF_SIZE_T)
+ DEBUGASSERT((size_t) sznum <= (size_t) CURL_MASK_SINT);
+#endif
+ return (int)(sznum & (ssize_t) CURL_MASK_SINT);
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+/*
+** signed int to unsigned size_t
+*/
+
+size_t curlx_sitouz(int sinum)
+{
+#ifdef __INTEL_COMPILER
+# pragma warning(push)
+# pragma warning(disable:810) /* conversion may lose significant bits */
+#endif
+
+ DEBUGASSERT(sinum >= 0);
+ return (size_t) sinum;
+
+#ifdef __INTEL_COMPILER
+# pragma warning(pop)
+#endif
+}
+
+#ifdef USE_WINSOCK
+
+/*
+** curl_socket_t to signed int
+*/
+
+int curlx_sktosi(curl_socket_t s)
+{
+ return (int)((ssize_t) s);
+}
+
+/*
+** signed int to curl_socket_t
+*/
+
+curl_socket_t curlx_sitosk(int i)
+{
+ return (curl_socket_t)((ssize_t) i);
+}
+
+#endif /* USE_WINSOCK */
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:1469) /* clobber ignored */
+ return FD_ISSET(fd, fdset);
+ #pragma warning(pop)
+}
+
+void curlx_FD_SET(int fd, fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:1469) /* clobber ignored */
+ FD_SET(fd, fdset);
+ #pragma warning(pop)
+}
+
+void curlx_FD_ZERO(fd_set *fdset)
+{
+ #pragma warning(push)
+ #pragma warning(disable:593) /* variable was set but never used */
+ FD_ZERO(fdset);
+ #pragma warning(pop)
+}
+
+unsigned short curlx_htons(unsigned short usnum)
+{
+#if (__INTEL_COMPILER == 910) && defined(__i386__)
+ return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF));
+#else
+ #pragma warning(push)
+ #pragma warning(disable:810) /* conversion may lose significant bits */
+ return htons(usnum);
+ #pragma warning(pop)
+#endif
+}
+
+unsigned short curlx_ntohs(unsigned short usnum)
+{
+#if (__INTEL_COMPILER == 910) && defined(__i386__)
+ return (unsigned short)(((usnum << 8) & 0xFF00) | ((usnum >> 8) & 0x00FF));
+#else
+ #pragma warning(push)
+ #pragma warning(disable:810) /* conversion may lose significant bits */
+ return ntohs(usnum);
+ #pragma warning(pop)
+#endif
+}
+
+#endif /* __INTEL_COMPILER && __unix__ */
diff --git a/libs/libcurl/src/warnless.h b/libs/libcurl/src/warnless.h
new file mode 100644
index 0000000000..f22f0bae4f
--- /dev/null
+++ b/libs/libcurl/src/warnless.h
@@ -0,0 +1,90 @@
+#ifndef HEADER_CURL_WARNLESS_H
+#define HEADER_CURL_WARNLESS_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.
+ *
+ ***************************************************************************/
+
+#ifdef USE_WINSOCK
+#include <curl/curl.h> /* for curl_socket_t */
+#endif
+
+unsigned short curlx_ultous(unsigned long ulnum);
+
+unsigned char curlx_ultouc(unsigned long ulnum);
+
+int curlx_ultosi(unsigned long ulnum);
+
+int curlx_uztosi(size_t uznum);
+
+unsigned long curlx_uztoul(size_t uznum);
+
+unsigned int curlx_uztoui(size_t uznum);
+
+int curlx_sltosi(long slnum);
+
+unsigned int curlx_sltoui(long slnum);
+
+unsigned short curlx_sltous(long slnum);
+
+ssize_t curlx_uztosz(size_t uznum);
+
+size_t curlx_sotouz(curl_off_t sonum);
+
+int curlx_sztosi(ssize_t sznum);
+
+size_t curlx_sitouz(int sinum);
+
+#ifdef USE_WINSOCK
+
+int curlx_sktosi(curl_socket_t s);
+
+curl_socket_t curlx_sitosk(int i);
+
+#endif /* USE_WINSOCK */
+
+#if defined(__INTEL_COMPILER) && defined(__unix__)
+
+int curlx_FD_ISSET(int fd, fd_set *fdset);
+
+void curlx_FD_SET(int fd, fd_set *fdset);
+
+void curlx_FD_ZERO(fd_set *fdset);
+
+unsigned short curlx_htons(unsigned short usnum);
+
+unsigned short curlx_ntohs(unsigned short usnum);
+
+#ifndef BUILDING_WARNLESS_C
+# undef FD_ISSET
+# define FD_ISSET(a,b) curlx_FD_ISSET((a),(b))
+# undef FD_SET
+# define FD_SET(a,b) curlx_FD_SET((a),(b))
+# undef FD_ZERO
+# define FD_ZERO(a) curlx_FD_ZERO((a))
+# undef htons
+# define htons(a) curlx_htons((a))
+# undef ntohs
+# define ntohs(a) curlx_ntohs((a))
+#endif
+
+#endif /* __INTEL_COMPILER && __unix__ */
+
+#endif /* HEADER_CURL_WARNLESS_H */
diff --git a/libs/libcurl/src/wildcard.c b/libs/libcurl/src/wildcard.c
new file mode 100644
index 0000000000..7130d5e494
--- /dev/null
+++ b/libs/libcurl/src/wildcard.c
@@ -0,0 +1,77 @@
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 1998 - 2010, 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 "wildcard.h"
+#include "llist.h"
+#include "fileinfo.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"
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc)
+{
+ DEBUGASSERT(wc->filelist == NULL);
+ /* now allocate only wc->filelist, everything else
+ will be allocated if it is needed. */
+ wc->filelist = Curl_llist_alloc(Curl_fileinfo_dtor);
+ if(!wc->filelist) {;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ return CURLE_OK;
+}
+
+void Curl_wildcard_dtor(struct WildcardData *wc)
+{
+ if(!wc)
+ return;
+
+ if(wc->tmp_dtor) {
+ wc->tmp_dtor(wc->tmp);
+ wc->tmp_dtor = ZERO_NULL;
+ wc->tmp = NULL;
+ }
+ DEBUGASSERT(wc->tmp == NULL);
+
+ if(wc->filelist) {
+ Curl_llist_destroy(wc->filelist, NULL);
+ wc->filelist = NULL;
+ }
+
+ if(wc->path) {
+ free(wc->path);
+ wc->path = NULL;
+ }
+
+ if(wc->pattern) {
+ free(wc->pattern);
+ wc->pattern = NULL;
+ }
+
+ wc->customptr = NULL;
+ wc->state = CURLWC_INIT;
+}
diff --git a/libs/libcurl/src/wildcard.h b/libs/libcurl/src/wildcard.h
new file mode 100644
index 0000000000..16c80ecbed
--- /dev/null
+++ b/libs/libcurl/src/wildcard.h
@@ -0,0 +1,58 @@
+#ifndef HEADER_CURL_WILDCARD_H
+#define HEADER_CURL_WILDCARD_H
+/***************************************************************************
+ * _ _ ____ _
+ * Project ___| | | | _ \| |
+ * / __| | | | |_) | |
+ * | (__| |_| | _ <| |___
+ * \___|\___/|_| \_\_____|
+ *
+ * Copyright (C) 2010 - 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/curl.h>
+
+/* list of wildcard process states */
+typedef enum {
+ CURLWC_INIT = 0,
+ CURLWC_MATCHING, /* library is trying to get list of addresses for
+ downloading */
+ CURLWC_DOWNLOADING,
+ CURLWC_CLEAN, /* deallocate resources and reset settings */
+ CURLWC_SKIP, /* skip over concrete file */
+ CURLWC_ERROR, /* error cases */
+ CURLWC_DONE /* if is wildcard->state == CURLWC_DONE wildcard loop
+ will end */
+} curl_wildcard_states;
+
+typedef void (*curl_wildcard_tmp_dtor)(void *ptr);
+
+/* struct keeping information about wildcard download process */
+struct WildcardData {
+ curl_wildcard_states state;
+ char *path; /* path to the directory, where we trying wildcard-match */
+ char *pattern; /* wildcard pattern */
+ struct curl_llist *filelist; /* llist with struct Curl_fileinfo */
+ void *tmp; /* pointer to protocol specific temporary data */
+ curl_wildcard_tmp_dtor tmp_dtor;
+ void *customptr; /* for CURLOPT_CHUNK_DATA pointer */
+};
+
+CURLcode Curl_wildcard_init(struct WildcardData *wc);
+void Curl_wildcard_dtor(struct WildcardData *wc);
+
+struct SessionHandle;
+
+#endif /* HEADER_CURL_WILDCARD_H */
diff --git a/libs/libcurl/src/x509asn1.c b/libs/libcurl/src/x509asn1.c
new file mode 100644
index 0000000000..94b89b2be0
--- /dev/null
+++ b/libs/libcurl/src/x509asn1.c
@@ -0,0 +1,1151 @@
+/***************************************************************************
+ * _ _ ____ _
+ * 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"
+
+#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+
+#include <curl/curl.h>
+#include "urldata.h"
+#include "strequal.h"
+#include "hostcheck.h"
+#include "sslgen.h"
+#include "sendf.h"
+#include "inet_pton.h"
+#include "curl_base64.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"
+
+
+/* ASN.1 OIDs. */
+static const char cnOID[] = "2.5.4.3"; /* Common name. */
+static const char sanOID[] = "2.5.29.17"; /* Subject alternative name. */
+
+static const curl_OID OIDtable[] = {
+ { "1.2.840.10040.4.1", "dsa" },
+ { "1.2.840.10040.4.3", "dsa-with-sha1" },
+ { "1.2.840.10045.2.1", "ecPublicKey" },
+ { "1.2.840.10045.3.0.1", "c2pnb163v1" },
+ { "1.2.840.10045.4.1", "ecdsa-with-SHA1" },
+ { "1.2.840.10046.2.1", "dhpublicnumber" },
+ { "1.2.840.113549.1.1.1", "rsaEncryption" },
+ { "1.2.840.113549.1.1.2", "md2WithRSAEncryption" },
+ { "1.2.840.113549.1.1.4", "md5WithRSAEncryption" },
+ { "1.2.840.113549.1.1.5", "sha1WithRSAEncryption" },
+ { "1.2.840.113549.1.1.10", "RSASSA-PSS" },
+ { "1.2.840.113549.1.1.14", "sha224WithRSAEncryption" },
+ { "1.2.840.113549.1.1.11", "sha256WithRSAEncryption" },
+ { "1.2.840.113549.1.1.12", "sha384WithRSAEncryption" },
+ { "1.2.840.113549.1.1.13", "sha512WithRSAEncryption" },
+ { "1.2.840.113549.2.2", "md2" },
+ { "1.2.840.113549.2.5", "md5" },
+ { "1.3.14.3.2.26", "sha1" },
+ { cnOID, "CN" },
+ { "2.5.4.4", "SN" },
+ { "2.5.4.5", "serialNumber" },
+ { "2.5.4.6", "C" },
+ { "2.5.4.7", "L" },
+ { "2.5.4.8", "ST" },
+ { "2.5.4.9", "streetAddress" },
+ { "2.5.4.10", "O" },
+ { "2.5.4.11", "OU" },
+ { "2.5.4.12", "title" },
+ { "2.5.4.13", "description" },
+ { "2.5.4.17", "postalCode" },
+ { "2.5.4.41", "name" },
+ { "2.5.4.42", "givenName" },
+ { "2.5.4.43", "initials" },
+ { "2.5.4.44", "generationQualifier" },
+ { "2.5.4.45", "X500UniqueIdentifier" },
+ { "2.5.4.46", "dnQualifier" },
+ { "2.5.4.65", "pseudonym" },
+ { "1.2.840.113549.1.9.1", "emailAddress" },
+ { "2.5.4.72", "role" },
+ { sanOID, "subjectAltName" },
+ { "2.5.29.18", "issuerAltName" },
+ { "2.5.29.19", "basicConstraints" },
+ { "2.16.840.1.101.3.4.2.4", "sha224" },
+ { "2.16.840.1.101.3.4.2.1", "sha256" },
+ { "2.16.840.1.101.3.4.2.2", "sha384" },
+ { "2.16.840.1.101.3.4.2.3", "sha512" },
+ { (const char *) NULL, (const char *) NULL }
+};
+
+/*
+ * Lightweight ASN.1 parser.
+ * In particular, it does not check for syntactic/lexical errors.
+ * It is intended to support certificate information gathering for SSL backends
+ * that offer a mean to get certificates as a whole, but do not supply
+ * entry points to get particular certificate sub-fields.
+ * Please note there is no pretention here to rewrite a full SSL library.
+ */
+
+
+const char * Curl_getASN1Element(curl_asn1Element * elem,
+ const char * beg, const char * end)
+{
+ unsigned char b;
+ unsigned long len;
+ curl_asn1Element lelem;
+
+ /* Get a single ASN.1 element into `elem', parse ASN.1 string at `beg'
+ ending at `end'.
+ Returns a pointer in source string after the parsed element, or NULL
+ if an error occurs. */
+
+ if(beg >= end || !*beg)
+ return (const char *) NULL;
+
+ /* Process header byte. */
+ b = (unsigned char) *beg++;
+ elem->constructed = (b & 0x20) != 0;
+ elem->class = (b >> 6) & 3;
+ b &= 0x1F;
+ if(b == 0x1F)
+ return (const char *) NULL; /* Long tag values not supported here. */
+ elem->tag = b;
+
+ /* Process length. */
+ if(beg >= end)
+ return (const char *) NULL;
+ b = (unsigned char) *beg++;
+ if(!(b & 0x80))
+ len = b;
+ else if(!(b &= 0x7F)) {
+ /* Unspecified length. Since we have all the data, we can determine the
+ effective length by skipping element until an end element is found. */
+ if(!elem->constructed)
+ return (const char *) NULL;
+ elem->beg = beg;
+ while(beg < end && *beg) {
+ beg = Curl_getASN1Element(&lelem, beg, end);
+ if(!beg)
+ return (const char *) NULL;
+ }
+ if(beg >= end)
+ return (const char *) NULL;
+ elem->end = beg;
+ return beg + 1;
+ }
+ else if(beg + b > end)
+ return (const char *) NULL; /* Does not fit in source. */
+ else {
+ /* Get long length. */
+ len = 0;
+ do {
+ if(len & 0xFF000000L)
+ return (const char *) NULL; /* Lengths > 32 bits are not supported. */
+ len = (len << 8) | (unsigned char) *beg++;
+ } while(--b);
+ }
+ if((unsigned long) (end - beg) < len)
+ return (const char *) NULL; /* Element data does not fit in source. */
+ elem->beg = beg;
+ elem->end = beg + len;
+ return elem->end;
+}
+
+static const curl_OID * searchOID(const char * oid)
+{
+ const curl_OID * op;
+
+ /* Search the null terminated OID or OID identifier in local table.
+ Return the table entry pointer or NULL if not found. */
+
+ for(op = OIDtable; op->numoid; op++)
+ if(!strcmp(op->numoid, oid) || curl_strequal(op->textoid, oid))
+ return op;
+
+ return (const curl_OID *) NULL;
+}
+
+static const char * bool2str(const char * beg, const char * end)
+{
+ /* Convert an ASN.1 Boolean value into its string representation.
+ Return the dynamically allocated string, or NULL if source is not an
+ ASN.1 Boolean value. */
+
+ if(end - beg != 1)
+ return (const char *) NULL;
+ return strdup(*beg? "TRUE": "FALSE");
+}
+
+static const char * octet2str(const char * beg, const char * end)
+{
+ size_t n = end - beg;
+ char * buf;
+
+ /* Convert an ASN.1 octet string to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ buf = malloc(3 * n + 1);
+ if(buf)
+ for(n = 0; beg < end; n += 3)
+ snprintf(buf + n, 4, "%02x:", *(const unsigned char *) beg++);
+ return buf;
+}
+
+static const char * bit2str(const char * beg, const char * end)
+
+{
+ /* Convert an ASN.1 bit string to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(++beg > end)
+ return (const char *) NULL;
+ return octet2str(beg, end);
+}
+
+static const char * int2str(const char * beg, const char * end)
+{
+ long val = 0;
+ size_t n = end - beg;
+
+ /* Convert an ASN.1 integer value into its string representation.
+ Return the dynamically allocated string, or NULL if source is not an
+ ASN.1 integer value. */
+
+ if(!n)
+ return (const char *) NULL;
+
+ if(n > 4)
+ return octet2str(beg, end);
+
+ /* Represent integers <= 32-bit as a single value. */
+ if(*beg & 0x80)
+ val = ~val;
+
+ do
+ val = (val << 8) | *(const unsigned char *) beg++;
+ while(beg < end);
+ return curl_maprintf("%s%lx", (val < 0 || val >= 10)? "0x": "", val);
+}
+
+static ssize_t
+utf8asn1str(char * * to, int type, const char * from, const char * end)
+{
+ size_t inlength = end - from;
+ int size = 1;
+ size_t outlength;
+ int chsize;
+ unsigned int wc;
+ char * buf;
+
+ /* Perform a lazy conversion from an ASN.1 typed string to UTF8. Allocate the
+ destination buffer dynamically. The allocation size will normally be too
+ large: this is to avoid buffer overflows.
+ Terminate the string with a nul byte and return the converted
+ string length. */
+
+ *to = (char *) NULL;
+ switch (type) {
+ case CURL_ASN1_BMP_STRING:
+ size = 2;
+ break;
+ case CURL_ASN1_UNIVERSAL_STRING:
+ size = 4;
+ break;
+ case CURL_ASN1_NUMERIC_STRING:
+ case CURL_ASN1_PRINTABLE_STRING:
+ case CURL_ASN1_TELETEX_STRING:
+ case CURL_ASN1_IA5_STRING:
+ case CURL_ASN1_VISIBLE_STRING:
+ case CURL_ASN1_UTF8_STRING:
+ break;
+ default:
+ return -1; /* Conversion not supported. */
+ }
+
+ if(inlength % size)
+ return -1; /* Length inconsistent with character size. */
+ buf = malloc(4 * (inlength / size) + 1);
+ if(!buf)
+ return -1; /* Not enough memory. */
+
+ if(type == CURL_ASN1_UTF8_STRING) {
+ /* Just copy. */
+ outlength = inlength;
+ if(outlength)
+ memcpy(buf, from, outlength);
+ }
+ else {
+ for(outlength = 0; from < end;) {
+ wc = 0;
+ switch (size) {
+ case 4:
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ case 2:
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ default: /* case 1: */
+ wc = (wc << 8) | *(const unsigned char *) from++;
+ }
+ chsize = 1;
+ if(wc >= 0x00000080) {
+ if(wc >= 0x00000800) {
+ if(wc >= 0x00010000) {
+ if(wc >= 0x00200000) {
+ free(buf);
+ return -1; /* Invalid char. size for target encoding. */
+ }
+ buf[outlength + 3] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x00010000;
+ chsize++;
+ }
+ buf[outlength + 2] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x00000800;
+ chsize++;
+ }
+ buf[outlength + 1] = (char) (0x80 | (wc & 0x3F));
+ wc = (wc >> 6) | 0x000000C0;
+ chsize++;
+ }
+ buf[outlength] = (char) wc;
+ outlength += chsize;
+ }
+ }
+ buf[outlength] = '\0';
+ *to = buf;
+ return outlength;
+}
+
+static const char * string2str(int type, const char * beg, const char * end)
+{
+ char * buf;
+
+ /* Convert an ASN.1 String into its UTF-8 string representation.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(utf8asn1str(&buf, type, beg, end) < 0)
+ return (const char *) NULL;
+ return buf;
+}
+
+static int encodeUint(char * buf, int n, unsigned int x)
+{
+ int i = 0;
+ unsigned int y = x / 10;
+
+ /* Decimal ASCII encode unsigned integer `x' in the `n'-byte buffer at `buf'.
+ Return the total number of encoded digits, even if larger than `n'. */
+
+ if(y) {
+ i += encodeUint(buf, n, y);
+ x -= y * 10;
+ }
+ if(i < n)
+ buf[i] = (char) ('0' + x);
+ i++;
+ if(i < n)
+ buf[i] = '\0'; /* Store a terminator if possible. */
+ return i;
+}
+
+static int encodeOID(char * buf, int n, const char * beg, const char * end)
+{
+ int i = 0;
+ unsigned int x;
+ unsigned int y;
+
+ /* Convert an ASN.1 OID into its dotted string representation.
+ Store the result in th `n'-byte buffer at `buf'.
+ Return the converted string length, or -1 if an error occurs. */
+
+ /* Process the first two numbers. */
+ y = *(const unsigned char *) beg++;
+ x = y / 40;
+ y -= x * 40;
+ i += encodeUint(buf + i, n - i, x);
+ if(i < n)
+ buf[i] = '.';
+ i++;
+ i += encodeUint(buf + i, n - i, y);
+
+ /* Process the trailing numbers. */
+ while(beg < end) {
+ if(i < n)
+ buf[i] = '.';
+ i++;
+ x = 0;
+ do {
+ if(x & 0xFF000000)
+ return -1;
+ y = *(const unsigned char *) beg++;
+ x = (x << 7) | (y & 0x7F);
+ } while(y & 0x80);
+ i += encodeUint(buf + i, n - i, x);
+ }
+ if(i < n)
+ buf[i] = '\0';
+ return i;
+}
+
+static const char * OID2str(const char * beg, const char * end, bool symbolic)
+{
+ char * buf = (char *) NULL;
+ const curl_OID * op;
+ int n;
+
+ /* Convert an ASN.1 OID into its dotted or symbolic string representation.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(beg < end) {
+ n = encodeOID((char *) NULL, -1, beg, end);
+ if(n >= 0) {
+ buf = malloc(n + 1);
+ if(buf) {
+ encodeOID(buf, n, beg, end);
+ buf[n] = '\0';
+
+ if(symbolic) {
+ op = searchOID(buf);
+ if(op) {
+ free(buf);
+ buf = strdup(op->textoid);
+ }
+ }
+ }
+ }
+ }
+ return buf;
+}
+
+static const char * GTime2str(const char * beg, const char * end)
+{
+ const char * tzp;
+ const char * fracp;
+ char sec1, sec2;
+ size_t fracl;
+ size_t tzl;
+ const char * sep = "";
+
+ /* Convert an ASN.1 Generalized time to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ for(fracp = beg; fracp < end && *fracp >= '0' && *fracp <= '9'; fracp++)
+ ;
+
+ /* Get seconds digits. */
+ sec1 = '0';
+ switch (fracp - beg - 12) {
+ case 0:
+ sec2 = '0';
+ break;
+ case 2:
+ sec1 = fracp[-2];
+ case 1:
+ sec2 = fracp[-1];
+ break;
+ default:
+ return (const char *) NULL;
+ }
+
+ /* Scan for timezone, measure fractional seconds. */
+ tzp = fracp;
+ fracl = 0;
+ if(fracp < end && (*fracp == '.' || *fracp == ',')) {
+ fracp++;
+ do
+ tzp++;
+ while(tzp < end && *tzp >= '0' && *tzp <= '9');
+ /* Strip leading zeroes in fractional seconds. */
+ for(fracl = tzp - fracp - 1; fracl && fracp[fracl - 1] == '0'; fracl--)
+ ;
+ }
+
+ /* Process timezone. */
+ if(tzp >= end)
+ ; /* Nothing to do. */
+ else if(*tzp == 'Z') {
+ tzp = " GMT";
+ end = tzp + 4;
+ }
+ else {
+ sep = " ";
+ tzp++;
+ }
+
+ tzl = end - tzp;
+ return curl_maprintf("%.4s-%.2s-%.2s %.2s:%.2s:%c%c%s%.*s%s%.*s",
+ beg, beg + 4, beg + 6,
+ beg + 8, beg + 10, sec1, sec2,
+ fracl? ".": "", fracl, fracp,
+ sep, tzl, tzp);
+}
+
+static const char * UTime2str(const char * beg, const char * end)
+{
+ const char * tzp;
+ size_t tzl;
+ const char * sec;
+
+ /* Convert an ASN.1 UTC time to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ for(tzp = beg; tzp < end && *tzp >= '0' && *tzp <= '9'; tzp++)
+ ;
+ /* Get the seconds. */
+ sec = beg + 10;
+ switch (tzp - sec) {
+ case 0:
+ sec = "00";
+ case 2:
+ break;
+ default:
+ return (const char *) NULL;
+ }
+
+ /* Process timezone. */
+ if(tzp >= end)
+ return (const char *) NULL;
+ if(*tzp == 'Z') {
+ tzp = "GMT";
+ end = tzp + 3;
+ }
+ else
+ tzp++;
+
+ tzl = end - tzp;
+ return curl_maprintf("%u%.2s-%.2s-%.2s %.2s:%.2s:%.2s %.*s",
+ 20 - (*beg >= '5'), beg, beg + 2, beg + 4,
+ beg + 6, beg + 8, sec,
+ tzl, tzp);
+}
+
+const char * Curl_ASN1tostr(curl_asn1Element * elem, int type)
+{
+ static const char zero = '\0';
+
+ /* Convert an ASN.1 element to a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(elem->constructed)
+ return (const char *) NULL; /* No conversion of structured elements. */
+
+ if(!type)
+ type = elem->tag; /* Type not forced: use element tag as type. */
+
+ switch (type) {
+ case CURL_ASN1_BOOLEAN:
+ return bool2str(elem->beg, elem->end);
+ case CURL_ASN1_INTEGER:
+ case CURL_ASN1_ENUMERATED:
+ return int2str(elem->beg, elem->end);
+ case CURL_ASN1_BIT_STRING:
+ return bit2str(elem->beg, elem->end);
+ case CURL_ASN1_OCTET_STRING:
+ return octet2str(elem->beg, elem->end);
+ case CURL_ASN1_NULL:
+ return strdup(&zero);
+ case CURL_ASN1_OBJECT_IDENTIFIER:
+ return OID2str(elem->beg, elem->end, TRUE);
+ case CURL_ASN1_UTC_TIME:
+ return UTime2str(elem->beg, elem->end);
+ case CURL_ASN1_GENERALIZED_TIME:
+ return GTime2str(elem->beg, elem->end);
+ case CURL_ASN1_UTF8_STRING:
+ case CURL_ASN1_NUMERIC_STRING:
+ case CURL_ASN1_PRINTABLE_STRING:
+ case CURL_ASN1_TELETEX_STRING:
+ case CURL_ASN1_IA5_STRING:
+ case CURL_ASN1_VISIBLE_STRING:
+ case CURL_ASN1_UNIVERSAL_STRING:
+ case CURL_ASN1_BMP_STRING:
+ return string2str(type, elem->beg, elem->end);
+ }
+
+ return (const char *) NULL; /* Unsupported. */
+}
+
+static ssize_t encodeDN(char * buf, size_t n, curl_asn1Element * dn)
+{
+ curl_asn1Element rdn;
+ curl_asn1Element atv;
+ curl_asn1Element oid;
+ curl_asn1Element value;
+ size_t l = 0;
+ const char * p1;
+ const char * p2;
+ const char * p3;
+ const char * str;
+
+ /* ASCII encode distinguished name at `dn' into the `n'-byte buffer at `buf'.
+ Return the total string length, even if larger than `n'. */
+
+ for(p1 = dn->beg; p1 < dn->end;) {
+ p1 = Curl_getASN1Element(&rdn, p1, dn->end);
+ for(p2 = rdn.beg; p2 < rdn.end;) {
+ p2 = Curl_getASN1Element(&atv, p2, rdn.end);
+ p3 = Curl_getASN1Element(&oid, atv.beg, atv.end);
+ Curl_getASN1Element(&value, p3, atv.end);
+ str = Curl_ASN1tostr(&oid, 0);
+ if(!str)
+ return -1;
+
+ /* Encode delimiter.
+ If attribute has a short uppercase name, delimiter is ", ". */
+ if(l) {
+ for(p3 = str; isupper(*p3); p3++)
+ ;
+ for(p3 = (*p3 || p3 - str > 2)? "/": ", "; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ }
+
+ /* Encode attribute name. */
+ for(p3 = str; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
+
+ /* Generate equal sign. */
+ if(l < n)
+ buf[l] = '=';
+ l++;
+
+ /* Generate value. */
+ str = Curl_ASN1tostr(&value, 0);
+ if(!str)
+ return -1;
+ for(p3 = str; *p3; p3++) {
+ if(l < n)
+ buf[l] = *p3;
+ l++;
+ }
+ free((char *) str);
+ }
+ }
+
+ return l;
+}
+
+const char * Curl_DNtostr(curl_asn1Element * dn)
+{
+ char * buf = (char *) NULL;
+ ssize_t n = encodeDN(buf, 0, dn);
+
+ /* Convert an ASN.1 distinguished name into a printable string.
+ Return the dynamically allocated string, or NULL if an error occurs. */
+
+ if(n >= 0) {
+ buf = malloc(n + 1);
+ if(buf) {
+ encodeDN(buf, n + 1, dn);
+ buf[n] = '\0';
+ }
+ }
+ return (const char *) buf;
+}
+
+static const char * checkOID(const char * beg, const char * end,
+ const char * oid)
+{
+ curl_asn1Element e;
+ const char * ccp;
+ const char * p;
+ bool matched;
+
+ /* Check if first ASN.1 element at `beg' is the given OID.
+ Return a pointer in the source after the OID if found, else NULL. */
+
+ ccp = Curl_getASN1Element(&e, beg, end);
+ if(!ccp || e.tag != CURL_ASN1_OBJECT_IDENTIFIER)
+ return (const char *) NULL;
+
+ p = OID2str(e.beg, e.end, FALSE);
+ if(!p)
+ return (const char *) NULL;
+
+ matched = !strcmp(p, oid);
+ free((char *) p);
+ return matched? ccp: (const char *) NULL;
+}
+
+
+/*
+ * X509 parser.
+ */
+
+void Curl_parseX509(curl_X509certificate * cert,
+ const char * beg, const char * end)
+{
+ curl_asn1Element elem;
+ curl_asn1Element tbsCertificate;
+ const char * ccp;
+ static const char defaultVersion = 0; /* v1. */
+
+ /* ASN.1 parse an X509 certificate into structure subfields.
+ Syntax is assumed to have already been checked by the SSL backend.
+ See RFC 5280. */
+
+ cert->certificate.beg = beg;
+ cert->certificate.end = end;
+
+ /* Get the sequence content. */
+ Curl_getASN1Element(&elem, beg, end);
+ beg = elem.beg;
+ end = elem.end;
+
+ /* Get tbsCertificate. */
+ beg = Curl_getASN1Element(&tbsCertificate, beg, end);
+ /* Skip the signatureAlgorithm. */
+ beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+ /* Get the signatureValue. */
+ Curl_getASN1Element(&cert->signature, beg, end);
+
+ /* Parse TBSCertificate. */
+ beg = tbsCertificate.beg;
+ end = tbsCertificate.end;
+ /* Get optional version, get serialNumber. */
+ cert->version.beg = &defaultVersion;
+ cert->version.end = &defaultVersion + sizeof defaultVersion;;
+ beg = Curl_getASN1Element(&elem, beg, end);
+ if(elem.tag == 0) {
+ Curl_getASN1Element(&cert->version, elem.beg, elem.end);
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ cert->serialNumber = elem;
+ /* Get signature algorithm. */
+ beg = Curl_getASN1Element(&cert->signatureAlgorithm, beg, end);
+ /* Get issuer. */
+ beg = Curl_getASN1Element(&cert->issuer, beg, end);
+ /* Get notBefore and notAfter. */
+ beg = Curl_getASN1Element(&elem, beg, end);
+ ccp = Curl_getASN1Element(&cert->notBefore, elem.beg, elem.end);
+ Curl_getASN1Element(&cert->notAfter, ccp, elem.end);
+ /* Get subject. */
+ beg = Curl_getASN1Element(&cert->subject, beg, end);
+ /* Get subjectPublicKeyAlgorithm and subjectPublicKey. */
+ beg = Curl_getASN1Element(&elem, beg, end);
+ ccp = Curl_getASN1Element(&cert->subjectPublicKeyAlgorithm,
+ elem.beg, elem.end);
+ Curl_getASN1Element(&cert->subjectPublicKey, ccp, elem.end);
+ /* Get optional issuerUiqueID, subjectUniqueID and extensions. */
+ cert->issuerUniqueID.tag = cert->subjectUniqueID.tag = 0;
+ cert->extensions.tag = elem.tag = 0;
+ cert->issuerUniqueID.beg = cert->issuerUniqueID.end = "";
+ cert->subjectUniqueID.beg = cert->subjectUniqueID.end = "";
+ cert->extensions.beg = cert->extensions.end = "";
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ if(elem.tag == 1) {
+ cert->issuerUniqueID = elem;
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ if(elem.tag == 2) {
+ cert->subjectUniqueID = elem;
+ if(beg < end)
+ beg = Curl_getASN1Element(&elem, beg, end);
+ }
+ if(elem.tag == 3)
+ Curl_getASN1Element(&cert->extensions, elem.beg, elem.end);
+}
+
+static size_t copySubstring(char * to, const char * from)
+{
+ size_t i;
+
+ /* Copy at most 64-characters, terminate with a newline and returns the
+ effective number of stored characters. */
+
+ for(i = 0; i < 64; i++) {
+ to[i] = *from;
+ if(!*from++)
+ break;
+ }
+
+ to[i++] = '\n';
+ return i;
+}
+
+static const char * dumpAlgo(curl_asn1Element * param,
+ const char * beg, const char * end)
+{
+ curl_asn1Element oid;
+
+ /* Get algorithm parameters and return algorithm name. */
+
+ beg = Curl_getASN1Element(&oid, beg, end);
+ param->tag = 0;
+ param->beg = param->end = end;
+ if(beg < end)
+ Curl_getASN1Element(param, beg, end);
+ return OID2str(oid.beg, oid.end, TRUE);
+}
+
+static void do_pubkey_field(struct SessionHandle *data, int certnum,
+ const char * label, curl_asn1Element * elem)
+{
+ const char * output;
+
+ /* Generate a certificate information record for the public key. */
+
+ output = Curl_ASN1tostr(elem, 0);
+ if(output) {
+ Curl_ssl_push_certinfo(data, certnum, label, output);
+ infof(data, " %s: %s\n", label, output);
+ free((char *) output);
+ }
+}
+
+static void do_pubkey(struct SessionHandle * data, int certnum,
+ const char * algo, curl_asn1Element * param,
+ curl_asn1Element * pubkey)
+{
+ curl_asn1Element elem;
+ curl_asn1Element pk;
+ const char * p;
+ const char * q;
+ unsigned long len;
+ unsigned int i;
+
+ /* Generate all information records for the public key. */
+
+ /* Get the public key (single element). */
+ Curl_getASN1Element(&pk, pubkey->beg + 1, pubkey->end);
+
+ if(curl_strequal(algo, "rsaEncryption")) {
+ p = Curl_getASN1Element(&elem, pk.beg, pk.end);
+ /* Compute key length. */
+ for(q = elem.beg; !*q && q < elem.end; q++)
+ ;
+ len = (elem.end - q) * 8;
+ if(len)
+ for(i = *(unsigned char *) q; !(i & 0x80); i <<= 1)
+ len--;
+ if(len > 32)
+ elem.beg = q; /* Strip leading zero bytes. */
+ infof(data, " RSA Public Key (%lu bits)\n", len);
+ q = curl_maprintf("%lu", len);
+ if(q) {
+ Curl_ssl_push_certinfo(data, certnum, "RSA Public Key", q);
+ free((char *) q);
+ }
+ /* Generate coefficients. */
+ do_pubkey_field(data, certnum, "rsa(n)", &elem);
+ Curl_getASN1Element(&elem, p, pk.end);
+ do_pubkey_field(data, certnum, "rsa(e)", &elem);
+ }
+ else if(curl_strequal(algo, "dsa")) {
+ p = Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dsa(p)", &elem);
+ p = Curl_getASN1Element(&elem, p, param->end);
+ do_pubkey_field(data, certnum, "dsa(q)", &elem);
+ Curl_getASN1Element(&elem, p, param->end);
+ do_pubkey_field(data, certnum, "dsa(g)", &elem);
+ do_pubkey_field(data, certnum, "dsa(pub_key)", &pk);
+ }
+ else if(curl_strequal(algo, "dhpublicnumber")) {
+ p = Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dh(p)", &elem);
+ Curl_getASN1Element(&elem, param->beg, param->end);
+ do_pubkey_field(data, certnum, "dh(g)", &elem);
+ do_pubkey_field(data, certnum, "dh(pub_key)", &pk);
+ }
+#if 0 /* Patent-encumbered. */
+ else if(curl_strequal(algo, "ecPublicKey")) {
+ /* Left TODO. */
+ }
+#endif
+}
+
+CURLcode Curl_extract_certinfo(struct connectdata * conn,
+ int certnum,
+ const char * beg,
+ const char * end)
+{
+ curl_X509certificate cert;
+ struct SessionHandle * data = conn->data;
+ curl_asn1Element param;
+ const char * ccp;
+ char * cp1;
+ size_t cl1;
+ char * cp2;
+ CURLcode cc;
+ unsigned long version;
+ size_t i;
+ size_t j;
+
+ /* Prepare the certificate information for curl_easy_getinfo(). */
+
+ /* Extract the certificate ASN.1 elements. */
+ Curl_parseX509(&cert, beg, end);
+
+ /* Subject. */
+ ccp = Curl_DNtostr(&cert.subject);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Subject", ccp);
+ infof(data, "%2d Subject: %s\n", certnum, ccp);
+ free((char *) ccp);
+
+ /* Issuer. */
+ ccp = Curl_DNtostr(&cert.issuer);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Issuer", ccp);
+ infof(data, " Issuer: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Version (always fits in less than 32 bits). */
+ version = 0;
+ for(ccp = cert.version.beg; ccp < cert.version.end; ccp++)
+ version = (version << 8) | *(const unsigned char *) ccp;
+ ccp = curl_maprintf("%lx", version);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Version", ccp);
+ free((char *) ccp);
+ infof(data, " Version: %lu (0x%lx)\n", version + 1, version);
+
+ /* Serial number. */
+ ccp = Curl_ASN1tostr(&cert.serialNumber, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Serial Number", ccp);
+ infof(data, " Serial Number: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Signature algorithm .*/
+ ccp = dumpAlgo(&param, cert.signatureAlgorithm.beg,
+ cert.signatureAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Signature Algorithm", ccp);
+ infof(data, " Signature Algorithm: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Start Date. */
+ ccp = Curl_ASN1tostr(&cert.notBefore, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Start Date", ccp);
+ infof(data, " Start Date: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Expire Date. */
+ ccp = Curl_ASN1tostr(&cert.notAfter, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Expire Date", ccp);
+ infof(data, " Expire Date: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Public Key Algorithm. */
+ ccp = dumpAlgo(&param, cert.subjectPublicKeyAlgorithm.beg,
+ cert.subjectPublicKeyAlgorithm.end);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Public Key Algorithm", ccp);
+ infof(data, " Public Key Algorithm: %s\n", ccp);
+ do_pubkey(data, certnum, ccp, &param, &cert.subjectPublicKey);
+ free((char *) ccp);
+
+/* TODO: extensions. */
+
+ /* Signature. */
+ ccp = Curl_ASN1tostr(&cert.signature, 0);
+ if(!ccp)
+ return CURLE_OUT_OF_MEMORY;
+ Curl_ssl_push_certinfo(data, certnum, "Signature", ccp);
+ infof(data, " Signature: %s\n", ccp);
+ free((char *) ccp);
+
+ /* Generate PEM certificate. */
+ cc = Curl_base64_encode(data, cert.certificate.beg,
+ cert.certificate.end - cert.certificate.beg,
+ &cp1, &cl1);
+ if(cc != CURLE_OK)
+ return cc;
+ /* Compute the number of charaters in final certificate string. Format is:
+ -----BEGIN CERTIFICATE-----\n
+ <max 64 base64 characters>\n
+ .
+ .
+ .
+ -----END CERTIFICATE-----\n
+ */
+ i = 28 + cl1 + (cl1 + 64 - 1) / 64 + 26;
+ cp2 = malloc(i + 1);
+ if(!cp2) {
+ free(cp1);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ /* Build the certificate string. */
+ i = copySubstring(cp2, "-----BEGIN CERTIFICATE-----");
+ for(j = 0; j < cl1; j += 64)
+ i += copySubstring(cp2 + i, cp1 + j);
+ i += copySubstring(cp2 + i, "-----END CERTIFICATE-----");
+ cp2[i] = '\0';
+ free(cp1);
+ Curl_ssl_push_certinfo(data, certnum, "Cert", cp2);
+ infof(data, "%s\n", cp2);
+ free(cp2);
+ return CURLE_OK;
+}
+
+
+CURLcode Curl_verifyhost(struct connectdata * conn,
+ const char * beg, const char * end)
+{
+ struct SessionHandle * data = conn->data;
+ curl_X509certificate cert;
+ curl_asn1Element dn;
+ curl_asn1Element elem;
+ curl_asn1Element ext;
+ curl_asn1Element name;
+ int i;
+ const char * p;
+ const char * q;
+ char * dnsname;
+ int matched = -1;
+ size_t addrlen = (size_t) -1;
+ ssize_t len;
+#ifdef ENABLE_IPV6
+ struct in6_addr addr;
+#else
+ struct in_addr addr;
+#endif
+
+ /* Verify that connection server matches info in X509 certificate at
+ `beg'..`end'. */
+
+ if(!data->set.ssl.verifyhost)
+ return CURLE_OK;
+
+ if(!beg)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ Curl_parseX509(&cert, beg, end);
+
+ /* Get the server IP address. */
+#ifdef ENABLE_IPV6
+ if(conn->bits.ipv6_ip && Curl_inet_pton(AF_INET6, conn->host.name, &addr))
+ addrlen = sizeof(struct in6_addr);
+ else
+#endif
+ if(Curl_inet_pton(AF_INET, conn->host.name, &addr))
+ addrlen = sizeof(struct in_addr);
+
+ /* Process extensions. */
+ for(p = cert.extensions.beg; p < cert.extensions.end && matched != 1;) {
+ p = Curl_getASN1Element(&ext, p, cert.extensions.end);
+ /* Check if extension is a subjectAlternativeName. */
+ ext.beg = checkOID(ext.beg, ext.end, sanOID);
+ if(ext.beg) {
+ ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+ /* Skip critical if present. */
+ if(elem.tag == CURL_ASN1_BOOLEAN)
+ ext.beg = Curl_getASN1Element(&elem, ext.beg, ext.end);
+ /* Parse the octet string contents: is a single sequence. */
+ Curl_getASN1Element(&elem, elem.beg, elem.end);
+ /* Check all GeneralNames. */
+ for(q = elem.beg; matched != 1 && q < elem.end;) {
+ q = Curl_getASN1Element(&name, q, elem.end);
+ switch (name.tag) {
+ case 2: /* DNS name. */
+ i = 0;
+ len = utf8asn1str(&dnsname, CURL_ASN1_IA5_STRING,
+ name.beg, name.end);
+ if(len > 0)
+ if(strlen(dnsname) == (size_t) len)
+ i = Curl_cert_hostcheck((const char *) dnsname, conn->host.name);
+ if(dnsname)
+ free(dnsname);
+ if(!i)
+ return CURLE_PEER_FAILED_VERIFICATION;
+ matched = i;
+ break;
+
+ case 7: /* IP address. */
+ matched = (size_t) (name.end - q) == addrlen &&
+ !memcmp(&addr, q, addrlen);
+ break;
+ }
+ }
+ }
+ }
+
+ switch (matched) {
+ case 1:
+ /* an alternative name matched the server hostname */
+ infof(data, "\t subjectAltName: %s matched\n", conn->host.dispname);
+ return CURLE_OK;
+ case 0:
+ /* an alternative name field existed, but didn't match and then
+ we MUST fail */
+ infof(data, "\t subjectAltName does not match %s\n", conn->host.dispname);
+ return CURLE_PEER_FAILED_VERIFICATION;
+ }
+
+ /* Process subject. */
+ name.beg = name.end = "";
+ q = cert.subject.beg;
+ /* we have to look to the last occurrence of a commonName in the
+ distinguished one to get the most significant one. */
+ while(q < cert.subject.end) {
+ q = Curl_getASN1Element(&dn, q, cert.subject.end);
+ for(p = dn.beg; p < dn.end;) {
+ p = Curl_getASN1Element(&elem, p, dn.end);
+ /* We have a DN's AttributeTypeAndValue: check it in case it's a CN. */
+ elem.beg = checkOID(elem.beg, elem.end, cnOID);
+ if(elem.beg)
+ name = elem; /* Latch CN. */
+ }
+ }
+
+ /* Check the CN if found. */
+ if(!Curl_getASN1Element(&elem, name.beg, name.end))
+ failf(data, "SSL: unable to obtain common name from peer certificate");
+ else {
+ len = utf8asn1str(&dnsname, elem.tag, elem.beg, elem.end);
+ if(len < 0) {
+ free(dnsname);
+ return CURLE_OUT_OF_MEMORY;
+ }
+ if(strlen(dnsname) != (size_t) len) /* Nul byte in string ? */
+ failf(data, "SSL: illegal cert name field");
+ else if(Curl_cert_hostcheck((const char *) dnsname, conn->host.name)) {
+ infof(data, "\t common name: %s (matched)\n", dnsname);
+ free(dnsname);
+ return CURLE_OK;
+ }
+ else
+ failf(data, "SSL: certificate subject name '%s' does not match "
+ "target host name '%s'", dnsname, conn->host.dispname);
+ free(dnsname);
+ }
+
+ return CURLE_PEER_FAILED_VERIFICATION;
+}
+
+#endif /* USE_QSOSSL or USE_GSKIT */
diff --git a/libs/libcurl/src/x509asn1.h b/libs/libcurl/src/x509asn1.h
new file mode 100644
index 0000000000..2276b5b641
--- /dev/null
+++ b/libs/libcurl/src/x509asn1.h
@@ -0,0 +1,129 @@
+#ifndef HEADER_CURL_X509ASN1_H
+#define HEADER_CURL_X509ASN1_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"
+
+#if defined(USE_QSOSSL) || defined(USE_GSKIT)
+
+#include "urldata.h"
+
+/*
+ * Constants.
+ */
+
+/* ASN.1 classes. */
+#define CURL_ASN1_UNIVERSAL 0
+#define CURL_ASN1_APPLICATION 1
+#define CURL_ASN1_CONTEXT_SPECIFIC 2
+#define CURL_ASN1_PRIVATE 3
+
+/* ASN.1 types. */
+#define CURL_ASN1_BOOLEAN 1
+#define CURL_ASN1_INTEGER 2
+#define CURL_ASN1_BIT_STRING 3
+#define CURL_ASN1_OCTET_STRING 4
+#define CURL_ASN1_NULL 5
+#define CURL_ASN1_OBJECT_IDENTIFIER 6
+#define CURL_ASN1_OBJECT_DESCRIPTOR 7
+#define CURL_ASN1_INSTANCE_OF 8
+#define CURL_ASN1_REAL 9
+#define CURL_ASN1_ENUMERATED 10
+#define CURL_ASN1_EMBEDDED 11
+#define CURL_ASN1_UTF8_STRING 12
+#define CURL_ASN1_RELATIVE_OID 13
+#define CURL_ASN1_SEQUENCE 16
+#define CURL_ASN1_SET 17
+#define CURL_ASN1_NUMERIC_STRING 18
+#define CURL_ASN1_PRINTABLE_STRING 19
+#define CURL_ASN1_TELETEX_STRING 20
+#define CURL_ASN1_VIDEOTEX_STRING 21
+#define CURL_ASN1_IA5_STRING 22
+#define CURL_ASN1_UTC_TIME 23
+#define CURL_ASN1_GENERALIZED_TIME 24
+#define CURL_ASN1_GRAPHIC_STRING 25
+#define CURL_ASN1_VISIBLE_STRING 26
+#define CURL_ASN1_GENERAL_STRING 27
+#define CURL_ASN1_UNIVERSAL_STRING 28
+#define CURL_ASN1_CHARACTER_STRING 29
+#define CURL_ASN1_BMP_STRING 30
+
+
+/*
+ * Types.
+ */
+
+/* ASN.1 parsed element. */
+typedef struct {
+ const char * beg; /* Pointer to element data. */
+ const char * end; /* Pointer to 1st byte after element data. */
+ unsigned char class; /* ASN.1 element class. */
+ unsigned char tag; /* ASN.1 element tag. */
+ bool constructed; /* Element is constructed. */
+} curl_asn1Element;
+
+
+/* ASN.1 OID table entry. */
+typedef struct {
+ const char * numoid; /* Dotted-numeric OID. */
+ const char * textoid; /* OID name. */
+} curl_OID;
+
+
+/* X509 certificate: RFC 5280. */
+typedef struct {
+ curl_asn1Element certificate;
+ curl_asn1Element version;
+ curl_asn1Element serialNumber;
+ curl_asn1Element signatureAlgorithm;
+ curl_asn1Element signature;
+ curl_asn1Element issuer;
+ curl_asn1Element notBefore;
+ curl_asn1Element notAfter;
+ curl_asn1Element subject;
+ curl_asn1Element subjectPublicKeyAlgorithm;
+ curl_asn1Element subjectPublicKey;
+ curl_asn1Element issuerUniqueID;
+ curl_asn1Element subjectUniqueID;
+ curl_asn1Element extensions;
+} curl_X509certificate;
+
+
+/*
+ * Prototypes.
+ */
+
+const char * Curl_getASN1Element(curl_asn1Element * elem,
+ const char * beg, const char * end);
+const char * Curl_ASN1tostr(curl_asn1Element * elem, int type);
+const char * Curl_DNtostr(curl_asn1Element * dn);
+void Curl_parseX509(curl_X509certificate * cert,
+ const char * beg, const char * end);
+CURLcode Curl_extract_certinfo(struct connectdata * conn, int certnum,
+ const char * beg, const char * end);
+CURLcode Curl_verifyhost(struct connectdata * conn,
+ const char * beg, const char * end);
+
+#endif /* USE_QSOSSL or USE_GSKIT */
+#endif /* HEADER_CURL_X509ASN1_H */
diff --git a/libs/libjson/libjson.vcxproj.filters b/libs/libjson/libjson.vcxproj.filters
index 001c820adb..de5ad9f66c 100644
--- a/libs/libjson/libjson.vcxproj.filters
+++ b/libs/libjson/libjson.vcxproj.filters
@@ -1,461 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(ProjectDir)..\..\build\vc.common\common.filters" />
- <ItemGroup>
- <ClCompile Include="src\stdafx.cxx">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- <ClCompile Include="src\internalJSONNode.cpp">
- <Filter>Source Files</Filter>
- </ClCompile>
- <ClCompile Include="src\JSONChildren.cpp" />
- <ClCompile Include="src\JSONDebug.cpp" />
- <ClCompile Include="src\JSONIterators.cpp" />
- <ClCompile Include="src\JSONMemory.cpp" />
- <ClCompile Include="src\JSONNode.cpp" />
- <ClCompile Include="src\JSONNode_Mutex.cpp" />
- <ClCompile Include="src\JSONWorker.cpp" />
- <ClCompile Include="src\JSONWriter.cpp" />
- <ClCompile Include="src\libJSON.cpp" />
- </ItemGroup>
- <ItemGroup>
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- <ClInclude Include="src\internalJSONNode.h">
- <Filter>Header Files</Filter>
- </ClInclude>
- <ClInclude Include="src\JSONChildren.h" />
- <ClInclude Include="src\JSONDebug.h" />
- <ClInclude Include="src\JSONDefs.h" />
- <ClInclude Include="src\JSONMemory.h" />
- <ClInclude Include="src\JSONNode.h" />
- <ClInclude Include="src\JSONOptions.h" />
- <ClInclude Include="src\JSONWorker.h" />
- <ClInclude Include="src\NumberToString.h" />
- <ClInclude Include="src\stdafx.h" />
- </ItemGroup>
- <ItemGroup>
- <None Include="src\libjson.def">
- <Filter>Source Files</Filter>
- </None>
- <None Include="src\libjson64.def" />
- <None Include="src\libjson.def">
- <Filter>Source Files</Filter>
- </None>
- <None Include="src\libjson64.def" />
- <None Include="src\libjson.def">
- <Filter>Source Files</Filter>
- </None>
- <None Include="src\libjson64.def" />
- </ItemGroup>
</Project> \ No newline at end of file