/// <summary> /// Extract <c>Slist</c> information from an <c>Easy</c> object. /// </summary> /// <param name="info">One of the values in the /// <see cref="CURLINFO"/> enumeration. In this case, it must /// specifically be one of the members that obtains an <c>Slist</c>. /// </param> /// <param name="slist">Reference to an <c>Slist</c> value.</param> /// <returns>The <see cref="CURLcode"/> obtained from the internal /// call to <c>curl_easy_getinfo()</c>. /// </returns> /// <exception cref="System.NullReferenceException">This is thrown if /// the native <c>CURL*</c> handle wasn't created successfully.</exception> public CURLcode GetInfo(CURLINFO info, ref Slist slist) { EnsureHandle(); CURLcode retCode = CURLcode.CURLE_OK; IntPtr ptr = IntPtr.Zero, ptrs = IntPtr.Zero; if ((int)info < CURLINFO_SLIST) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } retCode = External.curl_easy_getinfo(m_pCURL, info, ref ptr); if (retCode != CURLcode.CURLE_OK) { return(retCode); } slist = new Slist(); while (ptr != IntPtr.Zero) { ptr = External.curl_shim_get_string_from_slist( ptr, ref ptrs); slist.Append(Marshal.PtrToStringAnsi(ptrs)); } return(retCode); }
/// <summary> /// Set options for this object. See the <c>EasyGet</c> sample for /// basic usage. /// </summary> /// <param name="option">This should be a valid <see cref="CURLoption"/>.</param> /// <param name="parameter">This should be a parameter of a varying /// type based on the value of the <c>option</c> parameter.</param> /// <exception cref="System.NullReferenceException">This is thrown if /// the native <c>CURL*</c> handle wasn't created successfully.</exception> /// <returns>A <see cref="CURLcode"/>, typically obtained from /// <c>cURL</c> internally, but sometimes a /// <see cref="CURLcode.CURLE_BAD_FUNCTION_ARGUMENT"/> /// will be returned if the type of value of <c>parameter</c> is invalid. /// </returns> public CURLcode SetOpt(CURLoption option, Object parameter) { EnsureHandle(); CURLcode retCode = CURLcode.CURLE_OK; // numeric cases if ((int)option < CURLOPTTYPE_OBJECTPOINT) { int i = 0; if (option == CURLoption.CURLOPT_DNS_USE_GLOBAL_CACHE || option == CURLoption.CURLOPT_SOURCE_PORT) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } else if (option == CURLoption.CURLOPT_TIMEVALUE) { // unboxing may throw class cast exception DateTime d = (DateTime)parameter; DateTime startTime = new DateTime(1970, 1, 1); TimeSpan currTime = new TimeSpan(DateTime.Now.Ticks - startTime.Ticks); i = Convert.ToInt32(currTime.TotalSeconds); } else { i = Convert.ToInt32(parameter); } retCode = External.curl_easy_setopt(m_pCURL, option, (IntPtr)i); } // object cases: the majority else if ((int)option < CURLOPTTYPE_FUNCTIONPOINT) { switch (option) { // various data items case CURLoption.CURLOPT_PRIVATE: m_privateData = parameter; break; case CURLoption.CURLOPT_WRITEDATA: m_writeData = parameter; break; case CURLoption.CURLOPT_READDATA: m_readData = parameter; break; case CURLoption.CURLOPT_PROGRESSDATA: m_progressData = parameter; break; case CURLoption.CURLOPT_DEBUGDATA: m_debugData = parameter; break; case CURLoption.CURLOPT_HEADERDATA: m_headerData = parameter; break; case CURLoption.CURLOPT_SSL_CTX_DATA: m_sslContextData = parameter; break; case CURLoption.CURLOPT_IOCTLDATA: m_ioctlData = parameter; break; // items that can't be set externally or // obsolete items case CURLoption.CURLOPT_ERRORBUFFER: case CURLoption.CURLOPT_STDERR: case CURLoption.CURLOPT_SOURCE_HOST: case CURLoption.CURLOPT_SOURCE_PATH: case CURLoption.CURLOPT_PASV_HOST: return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); // singular case for share case CURLoption.CURLOPT_SHARE: { Share share = parameter as Share; if (share == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } retCode = External.curl_easy_setopt(m_pCURL, option, share.GetHandle()); break; } // multipart HTTP post case CURLoption.CURLOPT_HTTPPOST: { MultiPartForm mf = parameter as MultiPartForm; if (mf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } retCode = External.curl_easy_setopt(m_pCURL, option, mf.GetHandle()); break; } // items curl wants as a curl_slist case CURLoption.CURLOPT_HTTPHEADER: case CURLoption.CURLOPT_PREQUOTE: case CURLoption.CURLOPT_QUOTE: case CURLoption.CURLOPT_POSTQUOTE: case CURLoption.CURLOPT_SOURCE_QUOTE: case CURLoption.CURLOPT_TELNETOPTIONS: case CURLoption.CURLOPT_HTTP200ALIASES: { Slist slist = parameter as Slist; if (slist == null) { retCode = External.curl_easy_setopt(m_pCURL, option, IntPtr.Zero); } else { retCode = External.curl_easy_setopt(m_pCURL, option, slist.GetHandle()); } break; } // string items default: { string s = parameter as string; if (s == null) { retCode = External.curl_easy_setopt(m_pCURL, option, IntPtr.Zero); } else { IntPtr pCurlStr = External.curl_shim_add_string( m_pMyStrings, s); if (pCurlStr != IntPtr.Zero) { retCode = External.curl_easy_setopt(m_pCURL, option, pCurlStr); } } break; } } } // FUNCTIONPOINT args, for delegates else if ((int)option < CURLOPTTYPE_OFF_T) { switch (option) { case CURLoption.CURLOPT_WRITEFUNCTION: { WriteFunction wf = parameter as WriteFunction; if (wf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfWrite = wf; break; } case CURLoption.CURLOPT_READFUNCTION: { ReadFunction rf = parameter as ReadFunction; if (rf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfRead = rf; break; } case CURLoption.CURLOPT_PROGRESSFUNCTION: { ProgressFunction pf = parameter as ProgressFunction; if (pf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfProgress = pf; break; } case CURLoption.CURLOPT_DEBUGFUNCTION: { DebugFunction pd = parameter as DebugFunction; if (pd == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfDebug = pd; break; } case CURLoption.CURLOPT_HEADERFUNCTION: { HeaderFunction hf = parameter as HeaderFunction; if (hf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfHeader = hf; break; } case CURLoption.CURLOPT_SSL_CTX_FUNCTION: { SSLContextFunction sf = parameter as SSLContextFunction; if (sf == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfSSLContext = sf; break; } case CURLoption.CURLOPT_IOCTLFUNCTION: { IoctlFunction iof = parameter as IoctlFunction; if (iof == null) { return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } m_pfIoctl = iof; break; } default: return(CURLcode.CURLE_BAD_FUNCTION_ARGUMENT); } } // otherwise, it's one of those 64-bit off_t guys! else { Int64 i = Convert.ToInt64(parameter); retCode = External.curl_easy_setopt_64(m_pCURL, option, i); } return(retCode); }
/// <summary> /// Add a multi-part form section. /// </summary> /// <param name="args"> /// Argument list, as described in the remarks. /// </param> /// <returns> /// A <see cref="CURLFORMcode"/>, hopefully /// <c>CURLFORMcode.CURL_FORMADD_OK</c>. /// </returns> /// <remarks> /// This is definitely the workhorse method for this class. It /// should be called in roughly the same manner as /// <c>curl_formadd()</c>, except you would omit the first two /// <c>struct curl_httppost**</c> arguments (<c>firstitem</c> and /// <c>lastitem</c>), which are wrapped in this class. So you should /// pass arguments in the following sequence: /// <para> /// <c>MultiPartForm.AddSection(option1, value1, ..., optionX, valueX, /// CURLformoption.CURLFORM_END)</c>; /// </para> /// <para> /// For a complete list of possible options, see the documentation for /// the <see cref="CURLformoption"/> enumeration. /// </para> /// <note> /// The pointer options (<c>CURLFORM_PTRNAME</c>, etc.) make an /// internal copy of the passed <c>byte</c> array. Therefore, any /// changes you make to the client copy of this array AFTER calling /// this method, won't be reflected internally with <c>cURL</c>. The /// purpose of providing the pointer options is to support the /// posting of non-string binary data. /// </note> /// </remarks> public CURLFORMcode AddSection(params object[] args) { int nCount = args.Length; int nRealCount = nCount; CURLFORMcode retCode = CURLFORMcode.CURL_FORMADD_OK; CurlForms[] aForms = null; // one arg or even number of args is an error if ((nCount == 1) || (nCount % 2 == 0)) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } // ensure the last argument is CURLFORM_END CURLformoption iCode = (CURLformoption) Convert.ToInt32(args.GetValue(nCount - 1)); if (iCode != CURLformoption.CURLFORM_END) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } // walk through any passed arrays to get the true number of // items and ensure the child arrays are properly (and not // prematurely) terminated with CURLFORM_END for (int i = 0; i < nCount; i += 2) { iCode = (CURLformoption)Convert.ToInt32(args.GetValue(i)); switch (iCode) { case CURLformoption.CURLFORM_ARRAY: { aForms = args.GetValue(i + 1) as CurlForms[]; if (aForms == null) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } int nFormsCount = aForms.Length; for (int j = 0; j < nFormsCount; j++) { CurlForms pcf = aForms.GetValue(j) as CurlForms; if (pcf == null) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } if (j == nFormsCount - 1) { if (pcf.opt != CURLformoption.CURLFORM_END) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } } else { if (pcf.opt == CURLformoption.CURLFORM_END) { return(CURLFORMcode.CURL_FORMADD_INCOMPLETE); } } } // -2 accounts for the fact that we're a) not // including the item with CURLFORM_END and b) not // including CURLFORM_ARRAY in what we pass to cURL nRealCount += 2 * (nFormsCount - 2); break; } default: break; } } // allocate the IntPtr array for the data IntPtr[] aPointers = new IntPtr[nRealCount]; for (int i = 0; i < nRealCount - 1; i++) { aPointers[i] = IntPtr.Zero; } aPointers[nRealCount - 1] = (IntPtr)CURLformoption.CURLFORM_END; // now we go through the args aForms = null; int formArrayPos = 0; int argArrayPos = 0; int ptrArrayPos = 0; Object obj = null; while ((retCode == CURLFORMcode.CURL_FORMADD_OK) && (ptrArrayPos < nRealCount)) { if (aForms != null) { CurlForms pcf = aForms.GetValue(formArrayPos++) as CurlForms; if (pcf == null) { retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; break; } iCode = pcf.opt; obj = pcf.val; } else { iCode = (CURLformoption)Convert.ToInt32( args.GetValue(argArrayPos++)); obj = (iCode == CURLformoption.CURLFORM_END) ? null : args.GetValue(argArrayPos++); } switch (iCode) { // handle byte-array pointer-related items case CURLformoption.CURLFORM_PTRNAME: case CURLformoption.CURLFORM_PTRCONTENTS: case CURLformoption.CURLFORM_BUFFERPTR: { byte[] bytes = obj as byte[]; if (bytes == null) { retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; } else { int nLen = bytes.Length; IntPtr ptr = Marshal.AllocHGlobal(nLen); if (ptr != IntPtr.Zero) { aPointers[ptrArrayPos++] = (IntPtr)iCode; // copy bytes to unmanaged buffer for (int j = 0; j < nLen; j++) { Marshal.WriteByte(ptr, bytes[j]); } aPointers[ptrArrayPos++] = ptr; } else { retCode = CURLFORMcode.CURL_FORMADD_MEMORY; } } break; } // length values case CURLformoption.CURLFORM_NAMELENGTH: case CURLformoption.CURLFORM_CONTENTSLENGTH: case CURLformoption.CURLFORM_BUFFERLENGTH: aPointers[ptrArrayPos++] = (IntPtr)iCode; aPointers[ptrArrayPos++] = (IntPtr) Convert.ToInt32(obj); break; // strings case CURLformoption.CURLFORM_COPYNAME: case CURLformoption.CURLFORM_COPYCONTENTS: case CURLformoption.CURLFORM_FILECONTENT: case CURLformoption.CURLFORM_FILE: case CURLformoption.CURLFORM_CONTENTTYPE: case CURLformoption.CURLFORM_FILENAME: case CURLformoption.CURLFORM_BUFFER: { aPointers[ptrArrayPos++] = (IntPtr)iCode; string s = obj as String; if (s == null) { retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; } else { IntPtr p = Marshal.StringToHGlobalAnsi(s); if (p != IntPtr.Zero) { aPointers[ptrArrayPos++] = p; } else { retCode = CURLFORMcode.CURL_FORMADD_MEMORY; } } break; } // array case: already handled case CURLformoption.CURLFORM_ARRAY: if (aForms != null) { retCode = CURLFORMcode.CURL_FORMADD_ILLEGAL_ARRAY; } else { aForms = obj as CurlForms[]; if (aForms == null) { retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; } } break; // slist case CURLformoption.CURLFORM_CONTENTHEADER: { aPointers[ptrArrayPos++] = (IntPtr)iCode; Slist s = obj as Slist; if (s == null) { retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; } else { aPointers[ptrArrayPos++] = s.GetHandle(); } break; } // erroneous stuff case CURLformoption.CURLFORM_NOTHING: retCode = CURLFORMcode.CURL_FORMADD_INCOMPLETE; break; // end case CURLformoption.CURLFORM_END: if (aForms != null) // end of form { aForms = null; formArrayPos = 0; } else { aPointers[ptrArrayPos++] = (IntPtr)iCode; } break; // default is unknown default: retCode = CURLFORMcode.CURL_FORMADD_UNKNOWN_OPTION; break; } } // ensure we didn't come up short on parameters if (ptrArrayPos != nRealCount) { retCode = CURLFORMcode.CURL_FORMADD_INCOMPLETE; } // if we're OK here, call into curl if (retCode == CURLFORMcode.CURL_FORMADD_OK) { retCode = (CURLFORMcode)External.curl_shim_formadd( m_pItems, aPointers, nRealCount); } // unmarshal native allocations for (int i = 0; i < nRealCount - 1; i += 2) { iCode = (CURLformoption)(int)aPointers[i]; switch (iCode) { case CURLformoption.CURLFORM_COPYNAME: case CURLformoption.CURLFORM_COPYCONTENTS: case CURLformoption.CURLFORM_FILECONTENT: case CURLformoption.CURLFORM_FILE: case CURLformoption.CURLFORM_CONTENTTYPE: case CURLformoption.CURLFORM_FILENAME: case CURLformoption.CURLFORM_BUFFER: // byte buffer cases case CURLformoption.CURLFORM_PTRNAME: case CURLformoption.CURLFORM_PTRCONTENTS: case CURLformoption.CURLFORM_BUFFERPTR: { if (aPointers[i + 1] != IntPtr.Zero) { Marshal.FreeHGlobal(aPointers[i + 1]); } break; } default: break; } } return(retCode); }