/*************************************************************************** * * CurlS#arp * * Copyright (c) 2014 Dr. Masroor Ehsan (masroore@gmail.com) * Portions copyright (c) 2004, 2005 Jeff Phillips (jeff@jeffp.net) * * This software is licensed as described in the file LICENSE, which you * should have received as part of this distribution. * * You may opt to use, copy, modify, merge, publish, distribute and/or sell * copies of this Software, and permit persons to whom the Software is * furnished to do so, under the terms of the LICENSE file. * * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF * ANY KIND, either express or implied. * **************************************************************************/ using System; using System.Runtime.InteropServices; namespace CurlSharp { /// /// Implements the curl_easy_xxx API. /// /// /// This is the most important class in libcurl.NET. It wraps a /// CURL* handle and provides delegates through which callbacks /// (such as CurlWriteCallback and CurlReadCallback) /// are implemented. /// public class CurlEasy : IDisposable { // constants (used internally only) private const int CURLOPTTYPE_OBJECTPOINT = 10000; private const int CURLOPTTYPE_FUNCTIONPOINT = 20000; private const int CURLOPTTYPE_OFF_T = 30000; private const int CURLINFO_STRING = 0x100000; private const int CURLINFO_LONG = 0x200000; private const int CURLINFO_DOUBLE = 0x300000; private const int CURLINFO_SLIST = 0x400000; #if USE_LIBCURLSHIM private readonly IntPtr _pMyStrings; #endif private bool _autoReferer; private int _bufferSize; private string _caInfo; private string _caPath; private CurlClosePolicy _closePolicy; private int _connectTimeout; private string _cookie; private string _cookieFile; private string _cookieJar; private bool _cookieSession; private CurlShare _curlShare; private string _customRequest; private Object _debugData; private int _dnsCacheTimeout; private bool _dnsUseGlobalCache; private string _egdSocket; private string _encoding; private string _errorBuffer; private bool _failOnError; private bool _filetime; private bool _followLocation; private bool _forbidReuse; private bool _freshConnect; private string _ftpAccount; private bool _ftpAppend; private CurlFtpAuth _ftpAuth; private bool _ftpCreateMissingDirs; private bool _ftpListOnly; private string _ftpPort; private int _ftpResponseTimeout; private bool _ftpSkipPasvIp; private CurlFtpSsl _ftpSsl; private bool _ftpUseEprt; private bool _ftpUseEpsv; private GCHandle _hThis; private Object _headerData; private CurlHttpAuth _httpAuth; private bool _httpGet; private CurlHttpMultiPartForm _httpMultiPartForm; private bool _httpProxyTunnel; private CurlHttpVersion _httpVersion; private bool _ignoreContentLength; private long _infileSize; private string _interface; private Object _ioctlData; private string _krb4Level; private CurlCode _lastErrorCode; private string _lastErrorDescription; private int _lowSpeedLimit; private int _lowSpeedTime; private int _maxConnects; private long _maxFileSize; private int _maxRedirs; private string _netRcFile; private bool _noBody; private bool _noProgress; private bool _noSignal; private IntPtr _pCurl; #if USE_LIBCURLSHIM private NativeMethods._ShimDebugCallback _pcbDebug; private NativeMethods._ShimHeaderCallback _pcbHeader; private NativeMethods._ShimIoctlCallback _pcbIoctl; private NativeMethods._ShimProgressCallback _pcbProgress; private NativeMethods._ShimReadCallback _pcbRead; private NativeMethods._ShimSslCtxCallback _pcbSslCtx; private NativeMethods._ShimWriteCallback _pcbWrite; private IntPtr _ptrThis; #else private NativeMethods._CurlGenericCallback _pcbWrite; private NativeMethods._CurlGenericCallback _pcbRead; private NativeMethods._CurlGenericCallback _pcbHeader; private NativeMethods._CurlDebugCallback _pcbDebug; private NativeMethods._CurlIoctlCallback _pcbIoctl; private NativeMethods._CurlProgressCallback _pcbProgress; private NativeMethods._CurlSslCtxCallback _pcbSslCtx; #endif private CurlDebugCallback _pfCurlDebug; private CurlHeaderCallback _pfCurlHeader; private CurlIoctlCallback _pfCurlIoctl; private CurlProgressCallback _pfCurlProgress; private CurlReadCallback _pfCurlRead; private CurlSslContextCallback _pfCurlSslContext; private CurlWriteCallback _pfCurlWrite; private int _port; private bool _post; private int _postFieldSize; private string _postFields; private Object _privateData; private Object _progressData; private string _proxy; private int _proxyPort; private string _proxyUserPwd; private bool _put; private string _randomFile; private string _range; private Object _readData; private string _referer; private int _resumeFrom; private string _sourceUrl; private string _sslCert; private string _sslCertPasswd; private string _sslCipherList; private Object _sslContextData; private string _sslEngine; private bool _sslEngineDefault; private string _sslKey; private string _sslKeyPasswd; private bool _sslVerifyPeer; private bool _tcpNoDelay; private int _timeValue; private int _timeout; private bool _transferText; private bool _unrestrictedAuth; private bool _upload; private string _url; private string _userAgent; private string _userPwd; private bool _verbose; private Object _writeData; private string _writeInfo; /// /// Constructor /// /// /// This is thrown /// if hasn't bee properly initialized. /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlEasy() { Curl.EnsureCurl(); _pCurl = NativeMethods.curl_easy_init(); ensureHandle(); NativeMethods.curl_easy_setopt(_pCurl, CurlOption.NoProgress, IntPtr.Zero); #if USE_LIBCURLSHIM _pMyStrings = NativeMethods.curl_shim_alloc_strings(); #endif resetPrivateVariables(); installDelegates(); } private CurlEasy(CurlEasy from) { _pCurl = NativeMethods.curl_easy_duphandle(from._pCurl); ensureHandle(); #if USE_LIBCURLSHIM _pMyStrings = NativeMethods.curl_shim_alloc_strings(); #endif resetPrivateVariables(); installDelegates(); } public object Private { get { return _privateData; } set { _privateData = value; } } public object WriteData { get { return _writeData; } set { _writeData = value; #if !USE_LIBCURLSHIM setWriteData(value); #endif } } #if !USE_LIBCURLSHIM private IntPtr _curlWriteData = IntPtr.Zero; /// /// Object to pass to OnWriteCallback. /// /// /// private CurlCode setWriteData(object data) { _curlWriteData = getHandle(data); return setCurlOpt(_curlWriteData, CurlOption.WriteData); } private CurlCode setCurlOpt(IntPtr data, CurlOption opt) { var retCode = NativeMethods.curl_easy_setopt(_pCurl, opt, data); setLastError(retCode, opt); return retCode; } private IntPtr _curlReadData = IntPtr.Zero; /// /// Object to pass to OnReadCallback. /// Use to convert the passed IntPtr back into the object, then cast. /// /// /// private CurlCode setReadData(object data) { _curlReadData = getHandle(data); return setCurlOpt(_curlReadData, CurlOption.ReadData); } private IntPtr _curlProgressData = IntPtr.Zero; /// /// Object to pass to OnProgressCallback. /// Use to convert the passed IntPtr back into the object, then cast. /// /// /// private CurlCode setProgressData(object data) { _curlProgressData = getHandle(data); return setCurlOpt(_curlProgressData, CurlOption.ProgressData); } private IntPtr _curlHeaderData = IntPtr.Zero; /// /// Object to pass to OnHeaderCallback. /// /// /// private CurlCode setHeaderData(object data) { _curlHeaderData = getHandle(data); return setCurlOpt(_curlHeaderData, CurlOption.HeaderData); } private IntPtr _curlDebugData = IntPtr.Zero; /// /// Object to pass to OnDebugCallback. /// /// /// private CurlCode setDebugData(object data) { _curlDebugData = getHandle(data); return setCurlOpt(_curlDebugData, CurlOption.DebugData); } private IntPtr _curlSslCtxData = IntPtr.Zero; /// /// Object to pass to OnSslCtxCallback. /// /// /// private CurlCode setSslCtxData(object data) { _curlSslCtxData = getHandle(data); return setCurlOpt(_curlSslCtxData, CurlOption.SslCtxData); } private IntPtr _curlIoctlData = IntPtr.Zero; /// /// Object to pass to OnIoctlCallback. /// /// /// private CurlCode setIoctlData(object data) { _curlIoctlData = getHandle(data); return setCurlOpt(_curlIoctlData, CurlOption.IoctlData); } #endif public object ReadData { get { return _readData; } set { _readData = value; #if !USE_LIBCURLSHIM setReadData(value); #endif } } public object ProgressData { get { return _progressData; } set { _progressData = value; #if !USE_LIBCURLSHIM setProgressData(value); #endif } } public object DebugData { get { return _debugData; } set { _debugData = value; #if !USE_LIBCURLSHIM setDebugData(value); #endif } } public object HeaderData { get { return _headerData; } set { _headerData = value; #if !USE_LIBCURLSHIM setHeaderData(value); #endif } } public object SslCtxData { get { return _sslContextData; } set { _sslContextData = value; #if !USE_LIBCURLSHIM setSslCtxData(value); #endif } } public object IoctlData { get { return _ioctlData; } set { _ioctlData = value; #if !USE_LIBCURLSHIM setIoctlData(value); #endif } } public CurlShare Share { get { return _curlShare; } set { _curlShare = value; setShareObject(); } } public CurlHttpMultiPartForm HttpPost { get { return _httpMultiPartForm; } set { _httpMultiPartForm = value; setMultiPartFormObject(); } } public CurlSlist HttpHeader { set { setSlistObject(CurlOption.HttpHeader, value); } } public CurlSlist Prequote { set { setSlistObject(CurlOption.Prequote, value); } } public CurlSlist Quote { set { setSlistObject(CurlOption.Quote, value); } } public CurlSlist Postquote { set { setSlistObject(CurlOption.Postquote, value); } } public CurlSlist SourceQuote { set { setSlistObject(CurlOption.SourceQuote, value); } } public CurlSlist Http200Aliases { set { setSlistObject(CurlOption.Http200Aliases, value); } } public CurlFtpAuth FtpAuth { get { return _ftpAuth; } set { _ftpAuth = value; var l = Convert.ToInt32(value); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.FtpSslAuth, (IntPtr) l), CurlOption.FtpSslAuth); } } public CurlHttpVersion HttpVersion { get { return _httpVersion; } set { _httpVersion = value; var l = Convert.ToInt32(value); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpVersion, (IntPtr) l), CurlOption.HttpVersion); } } public CurlHttpAuth HttpAuth { get { return _httpAuth; } set { _httpAuth = value; var l = Convert.ToInt32(value); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpAuth, (IntPtr) l), CurlOption.HttpAuth); } } public CurlFtpSsl FtpSsl { get { return _ftpSsl; } set { _ftpSsl = value; var l = Convert.ToInt32(value); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.FtpSsl, (IntPtr) l), CurlOption.FtpSsl); } } public CurlClosePolicy ClosePolicy { get { return _closePolicy; } set { _closePolicy = value; var l = Convert.ToInt32(value); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.ClosePolicy, (IntPtr) l), CurlOption.ClosePolicy); } } public CurlWriteCallback WriteFunction { get { return _pfCurlWrite; } set { setFunctionOptions(CurlOption.WriteFunction, value); } } public CurlReadCallback ReadFunction { get { return _pfCurlRead; } set { setFunctionOptions(CurlOption.ReadFunction, value); } } public CurlHeaderCallback HeaderFunction { get { return _pfCurlHeader; } set { setFunctionOptions(CurlOption.HeaderFunction, value); } } public CurlDebugCallback DebugFunction { get { return _pfCurlDebug; } set { setFunctionOptions(CurlOption.DebugFunction, value); } } public CurlProgressCallback ProgressFunction { get { return _pfCurlProgress; } set { setFunctionOptions(CurlOption.ProgressFunction, value); } } public CurlIoctlCallback IoctlFunction { get { return _pfCurlIoctl; } set { setFunctionOptions(CurlOption.IoctlFunction, value); } } public CurlSslContextCallback SslContextFunction { get { return _pfCurlSslContext; } set { setFunctionOptions(CurlOption.SslCtxFunction, value); } } public string LastErrorDescription { get { return _lastErrorDescription; } } public bool NoProgress { get { return _noProgress; } set { setBoolOption(CurlOption.NoProgress, ref _noProgress, value); } } public bool NoBody { get { return _noBody; } set { setBoolOption(CurlOption.NoBody, ref _noBody, value); } } public bool FailOnError { get { return _failOnError; } set { setBoolOption(CurlOption.FailOnError, ref _failOnError, value); } } public bool Upload { get { return _upload; } set { setBoolOption(CurlOption.Upload, ref _upload, value); } } public bool Post { get { return _post; } set { setBoolOption(CurlOption.Post, ref _post, value); } } public bool FtpListOnly { get { return _ftpListOnly; } set { setBoolOption(CurlOption.FtpListOnly, ref _ftpListOnly, value); } } public bool FtpAppend { get { return _ftpAppend; } set { setBoolOption(CurlOption.FtpAppend, ref _ftpAppend, value); } } public bool FollowLocation { get { return _followLocation; } set { setBoolOption(CurlOption.FollowLocation, ref _followLocation, value); } } public bool TransferText { get { return _transferText; } set { setBoolOption(CurlOption.TransferText, ref _transferText, value); } } public bool Put { get { return _put; } set { setBoolOption(CurlOption.Put, ref _put, value); } } public bool HttpProxyTunnel { get { return _httpProxyTunnel; } set { setBoolOption(CurlOption.HttpProxyTunnel, ref _httpProxyTunnel, value); } } public bool SslVerifyPeer { get { return _sslVerifyPeer; } set { setBoolOption(CurlOption.SslVerifyPeer, ref _sslVerifyPeer, value); } } public bool FreshConnect { get { return _freshConnect; } set { setBoolOption(CurlOption.FreshConnect, ref _freshConnect, value); } } public bool ForbidReuse { get { return _forbidReuse; } set { setBoolOption(CurlOption.ForbidReuse, ref _forbidReuse, value); } } public bool HttpGet { get { return _httpGet; } set { setBoolOption(CurlOption.HttpGet, ref _httpGet, value); } } public bool FtpUseEpsv { get { return _ftpUseEpsv; } set { setBoolOption(CurlOption.FtpUseEpsv, ref _ftpUseEpsv, value); } } public bool Filetime { get { return _filetime; } set { setBoolOption(CurlOption.Filetime, ref _filetime, value); } } public bool UnrestrictedAuth { get { return _unrestrictedAuth; } set { setBoolOption(CurlOption.UnrestrictedAuth, ref _unrestrictedAuth, value); } } public bool FtpUseEprt { get { return _ftpUseEprt; } set { setBoolOption(CurlOption.FtpUseEprt, ref _ftpUseEprt, value); } } public bool AutoReferer { get { return _autoReferer; } set { setBoolOption(CurlOption.AutoReferer, ref _autoReferer, value); } } public bool CookieSession { get { return _cookieSession; } set { setBoolOption(CurlOption.CookieSession, ref _cookieSession, value); } } public bool SslEngineDefault { get { return _sslEngineDefault; } set { setBoolOption(CurlOption.SslEngineDefault, ref _sslEngineDefault, value); } } public bool DnsUseGlobalCache { get { return _dnsUseGlobalCache; } set { setBoolOption(CurlOption.DnsUseGlobalCache, ref _dnsUseGlobalCache, value); } } public bool NoSignal { get { return _noSignal; } set { setBoolOption(CurlOption.NoSignal, ref _noSignal, value); } } public bool FtpCreateMissingDirs { get { return _ftpCreateMissingDirs; } set { setBoolOption(CurlOption.FtpCreateMissingDirs, ref _ftpCreateMissingDirs, value); } } public bool TcpNoDelay { get { return _tcpNoDelay; } set { setBoolOption(CurlOption.TcpNoDelay, ref _tcpNoDelay, value); } } public bool IgnoreContentLength { get { return _ignoreContentLength; } set { setBoolOption(CurlOption.IgnoreContentLength, ref _ignoreContentLength, value); } } public bool FtpSkipPasvIp { get { return _ftpSkipPasvIp; } set { setBoolOption(CurlOption.FtpSkipPasvIp, ref _ftpSkipPasvIp, value); } } public int Port { get { return _port; } set { setIntOption(CurlOption.Port, ref _port, value); } } public int Timeout { get { return _timeout; } set { setIntOption(CurlOption.Timeout, ref _timeout, value); } } public int LowSpeedLimit { get { return _lowSpeedLimit; } set { setIntOption(CurlOption.LowSpeedLimit, ref _lowSpeedLimit, value); } } public int LowSpeedTime { get { return _lowSpeedTime; } set { setIntOption(CurlOption.LowSpeedTime, ref _lowSpeedTime, value); } } public int ResumeFrom { get { return _resumeFrom; } set { setIntOption(CurlOption.ResumeFrom, ref _resumeFrom, value); } } public int TimeValue { get { return _timeValue; } set { setIntOption(CurlOption.TimeValue, ref _timeValue, value); } } public int ProxyPort { get { return _proxyPort; } set { setIntOption(CurlOption.ProxyPort, ref _proxyPort, value); } } public int PostFieldSize { get { return _postFieldSize; } set { setIntOption(CurlOption.PostFieldSize, ref _postFieldSize, value); } } public int MaxRedirs { get { return _maxRedirs; } set { setIntOption(CurlOption.MaxRedirs, ref _maxRedirs, value); } } public int MaxConnects { get { return _maxConnects; } set { setIntOption(CurlOption.MaxConnects, ref _maxConnects, value); } } public int ConnectTimeout { get { return _connectTimeout; } set { setIntOption(CurlOption.ConnectTimeout, ref _connectTimeout, value); } } public int BufferSize { get { return _bufferSize; } set { setIntOption(CurlOption.BufferSize, ref _bufferSize, value); } } public int DnsCacheTimeout { get { return _dnsCacheTimeout; } set { setIntOption(CurlOption.DnsCacheTimeout, ref _dnsCacheTimeout, value); } } public int FtpResponseTimeout { get { return _ftpResponseTimeout; } set { setIntOption(CurlOption.FtpResponseTimeout, ref _ftpResponseTimeout, value); } } public long InfileSize { get { return _infileSize; } set { setLongOption(CurlOption.InfileSize, ref _infileSize, value); } } public long MaxFileSize { get { return _maxFileSize; } set { setLongOption(CurlOption.MaxFileSize, ref _maxFileSize, value); } } public string Url { get { return _url; } set { setStringOption(CurlOption.Url, out _url, value); } } public string Proxy { get { return _proxy; } set { setStringOption(CurlOption.Proxy, out _proxy, value); } } public string UserPwd { get { return _userPwd; } set { setStringOption(CurlOption.UserPwd, out _userPwd, value); } } public string ProxyUserPwd { get { return _proxyUserPwd; } set { setStringOption(CurlOption.ProxyUserPwd, out _proxyUserPwd, value); } } public string Range { get { return _range; } set { setStringOption(CurlOption.Range, out _range, value); } } public string PostFields { get { return _postFields; } set { setStringOption(CurlOption.PostFields, out _postFields, value); } } public string Referer { get { return _referer; } set { setStringOption(CurlOption.Referer, out _referer, value); } } public string FtpPort { get { return _ftpPort; } set { setStringOption(CurlOption.FtpPort, out _ftpPort, value); } } public string UserAgent { get { return _userAgent; } set { setStringOption(CurlOption.UserAgent, out _userAgent, value); } } public string Cookie { get { return _cookie; } set { setStringOption(CurlOption.Cookie, out _cookie, value); } } public string SslCert { get { return _sslCert; } set { setStringOption(CurlOption.SslCert, out _sslCert, value); } } public string SslCertPasswd { get { return _sslCertPasswd; } set { setStringOption(CurlOption.SslCertPasswd, out _sslCertPasswd, value); } } public string CustomRequest { get { return _customRequest; } set { setStringOption(CurlOption.CustomRequest, out _customRequest, value); } } public string Interface { get { return _interface; } set { setStringOption(CurlOption.Interface, out _interface, value); } } public string Encoding { get { return _encoding; } set { setStringOption(CurlOption.Encoding, out _encoding, value); } } public string Krb4Level { get { return _krb4Level; } set { setStringOption(CurlOption.Krb4Level, out _krb4Level, value); } } public string CaInfo { get { return _caInfo; } set { setStringOption(CurlOption.CaInfo, out _caInfo, value); } } public string RandomFile { get { return _randomFile; } set { setStringOption(CurlOption.RandomFile, out _randomFile, value); } } public string EgdSocket { get { return _egdSocket; } set { setStringOption(CurlOption.EgdSocket, out _egdSocket, value); } } public string CookieJar { get { return _cookieJar; } set { setStringOption(CurlOption.CookieJar, out _cookieJar, value); } } public string CookieFile { get { return _cookieFile; } set { setStringOption(CurlOption.CookieFile, out _cookieFile, value); } } public string SslCipherList { get { return _sslCipherList; } set { setStringOption(CurlOption.SslCipherList, out _sslCipherList, value); } } public string WriteInfo { get { return _writeInfo; } set { setStringOption(CurlOption.WriteInfo, out _writeInfo, value); } } public string CaPath { get { return _caPath; } set { setStringOption(CurlOption.CaPath, out _caPath, value); } } public string SslKey { get { return _sslKey; } set { setStringOption(CurlOption.SslKey, out _sslKey, value); } } public string SslEngine { get { return _sslEngine; } set { setStringOption(CurlOption.SslEngine, out _sslEngine, value); } } public string SslKeyPasswd { get { return _sslKeyPasswd; } set { setStringOption(CurlOption.SslKeyPasswd, out _sslKeyPasswd, value); } } public string ErrorBuffer { get { return _errorBuffer; } set { setStringOption(CurlOption.ErrorBuffer, out _errorBuffer, value); } } public string NetRcFile { get { return _netRcFile; } set { setStringOption(CurlOption.NetRcFile, out _netRcFile, value); } } public string FtpAccount { get { return _ftpAccount; } set { setStringOption(CurlOption.FtpAccount, out _ftpAccount, value); } } public string SourceUrl { get { return _sourceUrl; } set { setStringOption(CurlOption.SourceUrl, out _sourceUrl, value); } } public string EffectiveUrl { get { return getStringInfo(CurlInfo.EffectiveUrl); } } public string ContentType { get { return getStringInfo(CurlInfo.ContentType); } } public int ResponseCode { get { return getIntInfo(CurlInfo.ResponseCode); } } public int HeaderSize { get { return getIntInfo(CurlInfo.HeaderSize); } } public int RequestSize { get { return getIntInfo(CurlInfo.RequestSize); } } public bool Verbose { get { return _verbose; } set { setBoolOption(CurlOption.Verbose, ref _verbose, value); } } public int HttpAuthAvail { get { return getIntInfo(CurlInfo.HttpAuthAvail); } } public int SslVerifyResult { get { return getIntInfo(CurlInfo.SslVerifyResult); } } public int RedirectCount { get { return getIntInfo(CurlInfo.RedirectCount); } } public int ProxyAuthAvail { get { return getIntInfo(CurlInfo.ProxyAuthAvail); } } public int OsErrno { get { return getIntInfo(CurlInfo.OsErrno); } } public int NumConnects { get { return getIntInfo(CurlInfo.NumConnects); } } public int HttpConnectCode { get { return getIntInfo(CurlInfo.HttpConnectCode); } } public DateTime FileTime { get { return getDateTimeInfo(CurlInfo.Filetime); } } public double TotalTime { get { return getDoubleInfo(CurlInfo.TotalTime); } } public double NameLookupTime { get { return getDoubleInfo(CurlInfo.NameLookupTime); } } public double ConnectTime { get { return getDoubleInfo(CurlInfo.ConnectTime); } } public double PreTransferTime { get { return getDoubleInfo(CurlInfo.PreTransferTime); } } public double SizeUpload { get { return getDoubleInfo(CurlInfo.SizeUpload); } } public double SizeDownload { get { return getDoubleInfo(CurlInfo.SizeDownload); } } public double SpeedDownload { get { return getDoubleInfo(CurlInfo.SpeedDownload); } } public double SpeedUpload { get { return getDoubleInfo(CurlInfo.SpeedUpload); } } public double StartTransferTime { get { return getDoubleInfo(CurlInfo.StartTransferTime); } } public double ContentLengthDownload { get { return getDoubleInfo(CurlInfo.ContentLengthDownload); } } public double ContentLengthUpload { get { return getDoubleInfo(CurlInfo.ContentLengthUpload); } } public double RedirectTime { get { return getDoubleInfo(CurlInfo.RedirectTime); } } public CurlSlist SslEngines { get { return getSlistInfo(CurlInfo.SslEngines); } } public CurlCode LastErrorCode { get { return _lastErrorCode; } } /// /// Cleanup unmanaged resources. /// public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void resetPrivateVariables() { _privateData = null; _pfCurlWrite = null; _writeData = null; _pfCurlRead = null; _readData = null; _pfCurlProgress = null; _progressData = null; _pfCurlDebug = null; _debugData = null; _pfCurlHeader = null; _headerData = null; _pfCurlSslContext = null; _sslContextData = null; _pfCurlIoctl = null; _ioctlData = null; } private CurlCode setMultiPartFormObject() { ensureHandle(); var retCode = _httpMultiPartForm == null ? CurlCode.BadFunctionArgument : NativeMethods.curl_easy_setopt(_pCurl, CurlOption.HttpPost, _httpMultiPartForm.GetHandle()); setLastError(retCode, CurlOption.HttpPost); return retCode; } private CurlCode setSlistObject(CurlOption option, CurlSlist slist) { ensureHandle(); var retCode = NativeMethods.curl_easy_setopt(_pCurl, option, slist == null ? IntPtr.Zero : slist.Handle); setLastError(retCode, option); return retCode; } private CurlCode setShareObject() { ensureHandle(); var retCode = _curlShare == null ? CurlCode.BadFunctionArgument : NativeMethods.curl_easy_setopt(_pCurl, CurlOption.Share, _curlShare.GetHandle()); setLastError(retCode, CurlOption.Share); return retCode; } /// /// Handles return code from all calls to 'curl_easy_xxx' functions. /// private void setLastError(CurlCode code, CurlOption opt) { if (LastErrorCode == CurlCode.Ok && code != CurlCode.Ok) { _lastErrorCode = code; _lastErrorDescription = string.Format("Error: {0} setting option {1}", StrError(code), opt); } } /// /// Handles return code from all calls to 'curl_easy_xxx' functions. /// private void setLastError(CurlCode code, CurlInfo info) { if (LastErrorCode == CurlCode.Ok && code != CurlCode.Ok) { _lastErrorCode = code; _lastErrorDescription = string.Format("Error: {0} getting info {1}", StrError(code), info); } } /// /// Destructor /// ~CurlEasy() { Dispose(false); } private void Dispose(bool disposing) { lock (this) { if (disposing) { // free managed resources //if (managedResource != null) //{ // managedResource.Dispose(); // managedResource = null; //} } // free native resources if there are any. if (_pCurl != IntPtr.Zero) { #if USE_LIBCURLSHIM NativeMethods.curl_shim_cleanup_delegates(_ptrThis); NativeMethods.curl_shim_free_strings(_pMyStrings); #else freeHandle(ref _curlWriteData); freeHandle(ref _curlReadData); freeHandle(ref _curlDebugData); freeHandle(ref _curlProgressData); freeHandle(ref _curlHeaderData); freeHandle(ref _curlIoctlData); freeHandle(ref _curlSslCtxData); #endif NativeMethods.curl_easy_cleanup(_pCurl); _hThis.Free(); _pCurl = IntPtr.Zero; } } } private void ensureHandle() { if (_pCurl == IntPtr.Zero) throw new NullReferenceException("No internal easy handle"); } internal IntPtr Handle { get { ensureHandle(); return _pCurl; } } /// /// Reset the internal cURL handle. /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public void Reset() { ensureHandle(); NativeMethods.curl_easy_reset(_pCurl); } private void setBoolOption(CurlOption option, ref bool field, bool value) { ensureHandle(); field = value; setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) Convert.ToInt32(value)), option); } private void setIntOption(CurlOption option, ref int field, int value) { ensureHandle(); field = value; setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) value), option); } private void setLongOption(CurlOption option, ref long field, long value) { ensureHandle(); field = value; setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) value), option); } private void setStringOption(CurlOption option, out string field, string value) { setStringOption(option, value); field = value; } private void setStringOption(CurlOption option, string value) { ensureHandle(); if (string.IsNullOrEmpty(value)) { setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, IntPtr.Zero), option); } else { #if USE_LIBCURLSHIM var pCurlStr = NativeMethods.curl_shim_add_string(_pMyStrings, value); if (pCurlStr != IntPtr.Zero) setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, pCurlStr), option); #else // convert the string to a null-terminated one var buffer = System.Text.Encoding.UTF8.GetBytes(value + "\0"); setLastError(NativeMethods.curl_easy_setopt(_pCurl, option, buffer), option); #endif } } /// /// Set options for this object. See the EasyGet sample for /// basic usage. /// /// This should be a valid . /// /// This should be a parameter of a varying /// type based on the value of the option parameter. /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// /// /// A , typically obtained from /// cURL internally, but sometimes a /// /// will be returned if the type of value of parameter is invalid. /// public CurlCode SetOpt(CurlOption option, Object parameter) { ensureHandle(); var retCode = CurlCode.Ok; // numeric cases if ((int) option < CURLOPTTYPE_OBJECTPOINT) { var i = 0; if (option == CurlOption.DnsUseGlobalCache || option == CurlOption.SourcePort) { return CurlCode.BadFunctionArgument; } if (option == CurlOption.TimeValue) { // unboxing may throw class cast exception var d = (DateTime) parameter; var startTime = new DateTime(1970, 1, 1); var currTime = new TimeSpan(DateTime.Now.Ticks - startTime.Ticks); i = Convert.ToInt32(currTime.TotalSeconds); } else i = Convert.ToInt32(parameter); retCode = NativeMethods.curl_easy_setopt(_pCurl, option, (IntPtr) i); } // object cases: the majority else if ((int) option < CURLOPTTYPE_FUNCTIONPOINT) { return setObjectOptions(option, parameter); } // FUNCTIONPOINT args, for delegates else if ((int) option < CURLOPTTYPE_OFF_T) { return setFunctionOptions(option, parameter); } // otherwise, it's one of those 64-bit off_t guys! else { var i = Convert.ToInt64(parameter); retCode = NativeMethods.curl_easy_setopt(_pCurl, option, i); } return retCode; } private CurlCode setObjectOptions(CurlOption option, object parameter) { var retCode = CurlCode.Ok; switch (option) { // various data items case CurlOption.Private: _privateData = parameter; break; case CurlOption.WriteData: _writeData = parameter; break; case CurlOption.ReadData: _readData = parameter; break; case CurlOption.ProgressData: _progressData = parameter; break; case CurlOption.DebugData: _debugData = parameter; break; case CurlOption.HeaderData: _headerData = parameter; break; case CurlOption.SslCtxData: _sslContextData = parameter; break; case CurlOption.IoctlData: _ioctlData = parameter; break; // items that can't be set externally or // obsolete items case CurlOption.ErrorBuffer: case CurlOption.Stderr: case CurlOption.SourceHost: case CurlOption.SourcePath: case CurlOption.PasvHost: return CurlCode.BadFunctionArgument; // singular case for share case CurlOption.Share: { _curlShare = parameter as CurlShare; retCode = setShareObject(); break; } // multipart HTTP post case CurlOption.HttpPost: { _httpMultiPartForm = parameter as CurlHttpMultiPartForm; retCode = setMultiPartFormObject(); break; } // items curl wants as a curl_slist case CurlOption.HttpHeader: case CurlOption.Prequote: case CurlOption.Quote: case CurlOption.Postquote: case CurlOption.SourceQuote: case CurlOption.TelnetOptions: case CurlOption.Http200Aliases: { var slist = parameter as CurlSlist; retCode = setSlistObject(option, slist); break; } // string items default: { var s = parameter as string; setStringOption(option, s); retCode = _lastErrorCode; break; } } return retCode; } #if !USE_LIBCURLSHIM #region Object pinning support /// /// Free the pinned object /// /// private void freeHandle(ref IntPtr handle) { if (handle == IntPtr.Zero) return; var handleCallback = GCHandle.FromIntPtr(handle); handleCallback.Free(); handle = IntPtr.Zero; } /// /// Pin the object in memory so the C function can find it /// /// /// private static IntPtr getHandle(object obj) { if (obj == null) return IntPtr.Zero; return GCHandle.ToIntPtr(GCHandle.Alloc(obj, GCHandleType.Pinned)); } /// /// Returns the object passed to a Set...Data function. /// Cast back to the original object. /// /// /// private static object getObject(IntPtr userdata) { if (userdata == IntPtr.Zero) return null; var handle = GCHandle.FromIntPtr(userdata); return handle.Target; } #endregion #endif private CurlCode setFunctionOptions(CurlOption option, object pfn) { switch (option) { case CurlOption.WriteFunction: { var wf = pfn as CurlWriteCallback; if (wf == null) return CurlCode.BadFunctionArgument; _pfCurlWrite = wf; break; } case CurlOption.ReadFunction: { var rf = pfn as CurlReadCallback; if (rf == null) return CurlCode.BadFunctionArgument; _pfCurlRead = rf; break; } case CurlOption.ProgressFunction: { var pf = pfn as CurlProgressCallback; if (pf == null) return CurlCode.BadFunctionArgument; _pfCurlProgress = pf; break; } case CurlOption.DebugFunction: { var pd = pfn as CurlDebugCallback; if (pd == null) return CurlCode.BadFunctionArgument; _pfCurlDebug = pd; break; } case CurlOption.HeaderFunction: { var hf = pfn as CurlHeaderCallback; if (hf == null) return CurlCode.BadFunctionArgument; _pfCurlHeader = hf; break; } case CurlOption.SslCtxFunction: { var sf = pfn as CurlSslContextCallback; if (sf == null) return CurlCode.BadFunctionArgument; _pfCurlSslContext = sf; break; } case CurlOption.IoctlFunction: { var iof = pfn as CurlIoctlCallback; if (iof == null) return CurlCode.BadFunctionArgument; _pfCurlIoctl = iof; break; } default: return CurlCode.BadFunctionArgument; } return CurlCode.Ok; } /// /// Perform a transfer. /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// /// /// The obtained from the internal /// call to curl_easy_perform(). /// public CurlCode Perform() { ensureHandle(); return NativeMethods.curl_easy_perform(_pCurl); } /// /// Clone an CurlEasy object. /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// /// A cloned CurlEasy object. public CurlEasy Clone() { return new CurlEasy(this); } /// /// Get a string description of an error code. /// /// Error code. /// String description of the error code. public String StrError(CurlCode code) { return Marshal.PtrToStringAnsi(NativeMethods.curl_easy_strerror(code)); } /// /// Extract information from a cURL handle. /// /// /// One of the values in the /// enumeration. /// /// /// Reference to an object into which the /// value specified by info is written. /// /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref Object objInfo) { ensureHandle(); var retCode = CurlCode.Ok; var ptr = IntPtr.Zero; if ((int) info < CURLINFO_STRING) return CurlCode.BadFunctionArgument; // trickery for filetime if (info == CurlInfo.Filetime) return CurlCode.BadFunctionArgument; // private data if (info == CurlInfo.Private) { objInfo = _privateData; return retCode; } // string case if ((int) info < CURLINFO_LONG) { retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); if (retCode == CurlCode.Ok) objInfo = Marshal.PtrToStringAnsi(ptr); return retCode; } // int or double: return problem return CurlCode.BadFunctionArgument; } private string getStringInfo(CurlInfo info) { ensureHandle(); var ptr = IntPtr.Zero; var retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); setLastError(retCode, info); return retCode == CurlCode.Ok ? Marshal.PtrToStringAnsi(ptr) : string.Empty; } private int getIntInfo(CurlInfo info) { ensureHandle(); // ensure it's an integral type if ((int) info < CURLINFO_LONG || (int) info >= CURLINFO_DOUBLE) { setLastError(CurlCode.BadFunctionArgument, info); return -1; } var ptr = IntPtr.Zero; var retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); setLastError(retCode, info); return retCode == CurlCode.Ok ? (int) ptr : -1; } private DateTime getDateTimeInfo(CurlInfo info) { var dt = new DateTime(); setLastError(GetInfo(info, ref dt), info); return dt; } private double getDoubleInfo(CurlInfo info) { double val = 0; setLastError(GetInfo(info, ref val), info); return val; } private CurlSlist getSlistInfo(CurlInfo info) { CurlSlist val = null; setLastError(GetInfo(info, ref val), info); return val; } /// /// Extract CurlSlist information from an CurlEasy object. /// /// /// One of the values in the /// enumeration. In this case, it must /// specifically be one of the members that obtains an CurlSlist. /// /// Reference to an CurlSlist value. /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref CurlSlist slist) { ensureHandle(); var retCode = CurlCode.Ok; IntPtr ptr = IntPtr.Zero, ptrs = IntPtr.Zero; if ((int) info < CURLINFO_SLIST) return CurlCode.BadFunctionArgument; retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); if (retCode != CurlCode.Ok) return retCode; slist = new CurlSlist(); while (ptr != IntPtr.Zero) { #if USE_LIBCURLSHIM ptr = NativeMethods.curl_shim_get_string_from_slist(ptr, ref ptrs); slist.Append(Marshal.PtrToStringAnsi(ptrs)); #else //TODO: implement throw new NotImplementedException(); #endif } return retCode; } /// /// Extract string information from an CurlEasy object. /// /// /// One of the values in the /// enumeration. In this case, it must /// specifically be one of the members that obtains a string. /// /// Reference to an string value. /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref string strVal) { ensureHandle(); var retCode = CurlCode.Ok; var ptr = IntPtr.Zero; if ((int) info < CURLINFO_STRING || (int) info >= CURLINFO_LONG) return CurlCode.BadFunctionArgument; retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); if (retCode == CurlCode.Ok) strVal = Marshal.PtrToStringAnsi(ptr); return retCode; } /// /// Extract int information from an CurlEasy object. /// /// /// One of the values in the /// enumeration. In this case, it must /// specifically be one of the members that obtains a double. /// /// Reference to an double value. /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref double dblVal) { ensureHandle(); // ensure it's an integral type if ((int) info < CURLINFO_DOUBLE) return CurlCode.BadFunctionArgument; return NativeMethods.curl_easy_getinfo(_pCurl, info, ref dblVal); } /// /// Extract int information from an CurlEasy object. /// /// /// One of the values in the /// enumeration. In this case, it must /// specifically be one of the members that obtains an int. /// /// Reference to an int value. /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref int intVal) { ensureHandle(); var retCode = CurlCode.Ok; var ptr = IntPtr.Zero; // ensure it's an integral type if ((int) info < CURLINFO_LONG || (int) info >= CURLINFO_DOUBLE) return CurlCode.BadFunctionArgument; retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); if (retCode == CurlCode.Ok) intVal = (int) ptr; return retCode; } /// /// Extract DateTime information from an CurlEasy object. /// /// /// One of the values in the /// enumeration. In this case, it must /// specifically be . /// /// Reference to a DateTime value. /// /// The obtained from the internal /// call to curl_easy_getinfo(). /// /// /// This is thrown if /// the native CURL* handle wasn't created successfully. /// public CurlCode GetInfo(CurlInfo info, ref DateTime dt) { ensureHandle(); var retCode = CurlCode.Ok; var ptr = IntPtr.Zero; if (info != CurlInfo.Filetime) return CurlCode.BadFunctionArgument; retCode = NativeMethods.curl_easy_getinfo(_pCurl, info, ref ptr); if (retCode == CurlCode.Ok) { if ((int) ptr < 0) dt = new DateTime(0); } return retCode; } // install the fuctions that will be called from libcurlshim private void installDelegates() { ensureHandle(); _hThis = GCHandle.Alloc(this); #if USE_LIBCURLSHIM _pcbWrite = _shimWriteCallback; _pcbRead = _shimReadCallback; _pcbProgress = _shimProgressCallback; _pcbDebug = _shimDebugCallback; _pcbHeader = _shimHeaderCallback; _pcbSslCtx = _shimSslCtxCallback; _pcbIoctl = _shimIoctlCallback; _ptrThis = (IntPtr)_hThis; NativeMethods.curl_shim_install_delegates( _pCurl, _ptrThis, _pcbWrite, _pcbRead, _pcbProgress, _pcbDebug, _pcbHeader, _pcbSslCtx, _pcbIoctl); #else _pcbWrite = _curlWriteCallback; _pcbRead = _curlReadCallback; _pcbProgress = _curlProgressCallback; _pcbDebug = _curlDebugCallback; _pcbHeader = _curlHeaderCallback; _pcbSslCtx = _curlSslCtxCallback; _pcbIoctl = _curlIoctlCallback; setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.WriteFunction, _pcbWrite), CurlOption.WriteFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.ReadFunction, _pcbRead), CurlOption.ReadFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.ProgressFunction, _pcbProgress), CurlOption.ProgressFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.HeaderFunction, _pcbHeader), CurlOption.HeaderFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.DebugFunction, _pcbDebug), CurlOption.DebugFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.SslCtxFunction, _pcbSslCtx), CurlOption.SslCtxFunction); setLastError(NativeMethods.curl_easy_setopt_cb(_pCurl, CurlOption.IoctlFunction, _pcbIoctl), CurlOption.IoctlFunction); setLastError(NativeMethods.curl_easy_setopt(_pCurl, CurlOption.NoProgress, (IntPtr) 0), CurlOption.NoProgress); setWriteData(null); setReadData(null); setHeaderData(null); setProgressData(null); setDebugData(null); setSslCtxData(null); setIoctlData(null); #endif } #if USE_LIBCURLSHIM // called by libcurlshim private static int _shimWriteCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) { var bytes = sz*nmemb; var b = new byte[bytes]; for (var i = 0; i < bytes; i++) b[i] = Marshal.ReadByte(buf, i); var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return 0; if (curlEasy._pfCurlWrite == null) return bytes; // keep going return curlEasy._pfCurlWrite(b, sz, nmemb, curlEasy._writeData); } // called by libcurlshim private static int _shimReadCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) { var bytes = sz*nmemb; var b = new byte[bytes]; var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return 0; if (curlEasy._pfCurlRead == null) return 0; var nRead = curlEasy._pfCurlRead(b, sz, nmemb, curlEasy._readData); if (nRead > 0) { for (var i = 0; i < nRead; i++) Marshal.WriteByte(buf, i, b[i]); } return nRead; } // called by libcurlshim private static int _shimProgressCallback(IntPtr parm, double dlTotal, double dlNow, double ulTotal, double ulNow) { var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return 0; if (curlEasy._pfCurlProgress == null) return 0; var nprog = curlEasy._pfCurlProgress(curlEasy._progressData, dlTotal, dlNow, ulTotal, ulNow); return nprog; } // called by libcurlshim private static int _shimDebugCallback(CurlInfoType infoType, IntPtr msgBuf, int msgBufSize, IntPtr parm) { var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return 0; if (curlEasy._pfCurlDebug == null) return 0; var message = Marshal.PtrToStringAnsi(msgBuf, msgBufSize); curlEasy._pfCurlDebug(infoType, message, curlEasy._debugData); return 0; } // called by libcurlshim private static int _shimHeaderCallback(IntPtr buf, int sz, int nmemb, IntPtr parm) { var bytes = sz*nmemb; var b = new byte[bytes]; for (var i = 0; i < bytes; i++) b[i] = Marshal.ReadByte(buf, i); var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return 0; if (curlEasy._pfCurlHeader == null) return bytes; // keep going return curlEasy._pfCurlHeader(b, sz, nmemb, curlEasy._headerData); } // called by libcurlshim private static int _shimSslCtxCallback(IntPtr ctx, IntPtr parm) { const int OK_RETURN = (int) CurlCode.Ok; var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; if (curlEasy == null) return OK_RETURN; if (curlEasy._pfCurlSslContext == null) return OK_RETURN; // keep going var context = new CurlSslContext(ctx); return (int) curlEasy._pfCurlSslContext(context, curlEasy._sslContextData); } // called by libcurlshim private static CurlIoError _shimIoctlCallback(CurlIoCommand cmd, IntPtr parm) { var gch = (GCHandle) parm; var curlEasy = (CurlEasy) gch.Target; // let's require all of these to be non-null if (curlEasy == null || curlEasy._pfCurlIoctl == null || curlEasy._ioctlData == null) { return CurlIoError.UnknownCommand; } return curlEasy._pfCurlIoctl(cmd, curlEasy._ioctlData); } #else // called by libcurl private int _curlWriteCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserData) { var bytes = sz*nmemb; if (_pfCurlWrite == null) return bytes; // keep going var buf = new byte[bytes]; Marshal.Copy(pBuffer, buf, 0, bytes); var userdata = getObject(pUserData); return _pfCurlWrite(buf, sz, nmemb, userdata); } private int _curlReadCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserData) { var bytes = sz*nmemb; if (_pfCurlRead == null) return bytes; // keep going var userdata = getObject(pUserData); var buffer = new byte[bytes]; var nRead = _pfCurlRead(buffer, sz, nmemb, userdata); if (nRead > 0) Marshal.Copy(buffer, 0, pBuffer, nRead); return nRead; } private int _curlProgressCallback(IntPtr ptrUserdata, double dlTotal, double dlNow, double ulTotal, double ulNow) { if (_pfCurlProgress != null) { var userdata = getObject(ptrUserdata); return _pfCurlProgress(userdata, dlTotal, dlNow, ulTotal, ulNow); } return 0; } private int _curlDebugCallback(IntPtr pCurl, CurlInfoType infoType, string message, int size, IntPtr pUserData) { if (_pfCurlDebug != null) { var userdata = getObject(pUserData); _pfCurlDebug(infoType, message, userdata); } return 0; } private int _curlHeaderCallback(IntPtr pBuffer, int sz, int nmemb, IntPtr pUserdata) { var bytes = sz*nmemb; if (_pfCurlHeader != null) { var buf = new byte[bytes]; Marshal.Copy(pBuffer, buf, 0, bytes); var userdata = getObject(pUserdata); return _pfCurlHeader(buf, sz, nmemb, userdata); } return bytes; // keep going } private int _curlSslCtxCallback(IntPtr ctx, IntPtr parm) { if (_pfCurlSslContext == null) return (int) CurlCode.Ok; // keep going var context = new CurlSslContext(ctx); return (int) _pfCurlSslContext(context, _sslContextData); } private CurlIoError _curlIoctlCallback(CurlIoCommand cmd, IntPtr parm) { if (_pfCurlIoctl == null || _ioctlData == null) return CurlIoError.UnknownCommand; return _pfCurlIoctl(cmd, _ioctlData); } #endif } }