public CURLE Perform() { CURLE result = (CURLE)(-1); if (!running) { running = true; retryCount = maxRetryCount; while (true) { Prepare(); result = Lib.curl_easy_perform(easyPtr); var done = ProcessResponse(result); if (done || --retryCount < 0) { Dump(); break; } else { Thread.Sleep(retryInterval); } } running = false; } else { CurlLog.LogError("Can't preform a running handle again!"); } return(result); }
private void Awake() { if (CurlLog.Assert(instance == null, "Only one CurlMultiUpdater instance is allowed")) { instance = this; } }
private void Awake() { CurlLog.Assert(instance == null, "Only one CurlMultiUpdater instance is allowed"); if (instance == null) { instance = this; } defaultMulti = new CurlMulti(); }
internal void RemoveEasy(CurlEasy easy) { lock (this) { var res = Lib.curl_multi_remove_handle(multiPtr, (IntPtr)easy); CurlLog.Assert(res == CURLM.OK, $"RemoveEasy {res}"); } lock (workingEasies) { workingEasies.Remove((IntPtr)easy); } }
private static int DebugFunction(IntPtr ptr, CURLINFODEBUG type, IntPtr data, int size, IntPtr userdata) { if (type == CURLINFODEBUG.HEADER_OUT) { StreamReader sr = null; var thiz = ((GCHandle)userdata).Target as CurlEasy; #if ALLOW_UNSAFE unsafe { var ums = new UnmanagedMemoryStream((byte *)data, (int)size); sr = new StreamReader(ums); } #else var bytes = thiz.AcquireBuffer(size); Marshal.Copy(data, bytes, 0, (int)size); sr = new StreamReader(new MemoryStream(bytes, 0, (int)size)); #endif // Handle first line var firstLine = sr.ReadLine(); while (true) { var line = sr.ReadLine(); if (!string.IsNullOrEmpty(line)) { var index = line.IndexOf(':'); if (index >= 0) { if (thiz.outHeader == null) { thiz.outHeader = new HeaderDict(); } var key = line.Substring(0, index).Trim(); var value = line.Substring(index + 1).Trim(); thiz.outHeader[key] = value; } else { CurlLog.LogWarning($"Invalid header: {line}"); } } else { break; } } } return(0); }
internal void AddEasy(CurlEasy easy) { lock (this) { var wc = workingEasies.Count; var res = Lib.curl_multi_add_handle(multiPtr, (IntPtr)easy); CurlLog.Assert(res == CURLM.OK, $"AddEasy {easy.uri} {res} {wc}"); easy.SetOpt(CURLOPT.SHARE, (IntPtr)share); } lock (workingEasies) { workingEasies[(IntPtr)easy] = easy; } }
internal int Perform() { if (!started) { return(0); } long running = 0; if (multiPtr != IntPtr.Zero) { lock (this) { var res = Lib.curl_multi_perform(multiPtr, ref running); CurlLog.Assert(res == CURLM.OK, $"Perform {res}"); } while (true) { long index = 0; var msgPtr = Lib.curl_multi_info_read(multiPtr, ref index); if (msgPtr != IntPtr.Zero) { var msg = (CurlMsg)msgPtr; if (msg.message == CURLMSG.DONE) { CurlEasy easy = null; lock (workingEasies) { workingEasies.TryGetValue(msg.easyPtr, out easy); } if (easy != null) { RemoveEasy(easy); easy.OnMultiPerform(msg.result, this); } } } else { break; } } } return((int)running); }
public void MultiPerform(CurlMulti _multi = null) { if (!running) { running = true; retryCount = maxRetryCount; multi = _multi ?? CurlMultiUpdater.Instance.DefaultMulti; Prepare(); multi.AddEasy(this); } else { CurlLog.LogError("Can't preform a running handle again!"); } }
private void Dump() { if (!dump) { return; } try { var sb = new StringBuilder(); GetInfo(CURLINFO.EFFECTIVE_URL, out string effectiveUrl); GetInfo(CURLINFO.TOTAL_TIME, out double time); GetInfo(CURLINFO.PRIMARY_IP, out string ip); #if UNITY_EDITOR var colorize = true; #else var colorize = false; #endif if (colorize) { sb.AppendLine($"<color={((status >= 200 && status <= 299) ? "green" : "red")}><b>[{method.ToUpper()}]</b></color> {effectiveUrl}({ip}) [{httpVersion} {status} {message}] [{outDataLength}({(outData != null ? outData.Length : 0)}) | {inDataLength}({(inData != null ? inData.Length : 0)}) | {time * 1000} ms]"); } else { sb.AppendLine($"[{method.ToUpper()}] {effectiveUrl}({ip}) [{httpVersion} {status} {message}] [{outDataLength}({(outData != null ? outData.Length : 0)}) | {inDataLength}({(inData != null ? inData.Length : 0)}) | {time * 1000} ms]"); } if (debug) { if (outHeader != null) { if (colorize) { sb.AppendLine("<b><color=lightblue>Request Headers</color></b>"); } else { sb.AppendLine("-- Request Headers --"); } foreach (var entry in outHeader) { if (colorize) { sb.AppendLine($"<b><color=silver>[{entry.Key}]</color></b> {entry.Value}"); } else { sb.AppendLine($"[{entry.Key}] {entry.Value}"); } } } if (outData != null && outData.Length > 0) { if (colorize) { sb.AppendLine($"<b><color=lightblue>Request Body</color></b> [ {outData.Length} ]"); } else { sb.AppendLine($"-- Request Body -- [ {outData.Length} ]"); } string outDataString = decoder?.DecodeOutData(this) ?? Encoding.UTF8.GetString(outData, 0, Math.Min(outData.Length, 0x400)); sb.AppendLine(outDataString); } if (inHeader != null) { if (colorize) { sb.AppendLine("<b><color=lightblue>Response Headers</color></b>"); } else { sb.AppendLine("-- Response Headers --"); } foreach (var entry in inHeader) { if (colorize) { sb.AppendLine($"<b><color=silver>[{entry.Key}]</color></b> {entry.Value}"); } else { sb.AppendLine($"[{entry.Key}] {entry.Value}"); } } } if (inData != null && inData.Length > 0) { if (colorize) { sb.AppendLine($"<b><color=lightblue>Response Body</color></b> [ {inData.Length} ]"); } else { sb.AppendLine($"-- Response Body -- [ {inData.Length} ]"); } string inDataString = decoder?.DecodeInData(this) ?? Encoding.UTF8.GetString(inData, 0, Math.Min(inData.Length, 0x400)); sb.AppendLine(inDataString); } } CurlLog.Log(sb.ToString()); } catch (Exception e) { CurlLog.LogError("Unexpected exception: " + e); } }
private bool ProcessResponse(CURLE result) { var done = false; try { thisHandle.Free(); if (result == CURLE.OK) { responseHeaderStream.Position = 0; var sr = new StreamReader(responseHeaderStream); // Handle first line { var line = sr.ReadLine(); var index = line.IndexOf(' '); httpVersion = line.Substring(0, index); var nextIndex = line.IndexOf(' ', index + 1); if (int.TryParse(line.Substring(index + 1, nextIndex - index), out var _status)) { status = _status; } message = line.Substring(nextIndex + 1); } inHeader = new HeaderDict(); while (true) { var line = sr.ReadLine(); if (!string.IsNullOrEmpty(line)) { var index = line.IndexOf(':'); var key = line.Substring(0, index).Trim(); var value = line.Substring(index + 1).Trim(); inHeader[key] = value; } else { break; } } var ms = responseBodyStream as MemoryStream; if (ms != null) { inData = ms.ToArray(); } if (status / 100 == 3) { if (followRedirect && GetInfo(CURLINFO.REDIRECT_URL, out string location) == CURLE.OK) { uri = new Uri(location); } else { done = true; } } else { done = true; } } else { CurlLog.LogWarning($"Failed to request: {uri}, reason: {result}"); } CloseStreams(); } catch (Exception e) { CurlLog.LogError("Unexpected exception: " + e); } return(done); }
private void Prepare() { try { status = 0; message = null; thisHandle = GCHandle.Alloc(this); SetOpt(CURLOPT.URL, uri.AbsoluteUri); var upperMethod = method.ToUpper(); switch (upperMethod) { case "GET": SetOpt(CURLOPT.HTTPGET, true); break; case "HEAD": SetOpt(CURLOPT.NOBODY, true); break; case "POST": SetOpt(CURLOPT.POST, true); break; default: SetOpt(CURLOPT.CUSTOMREQUEST, method); break; } if (useHttp2) { SetOpt(CURLOPT.HTTP_VERSION, (long)HTTPVersion.VERSION_2TLS); } else { SetOpt(CURLOPT.HTTP_VERSION, (long)HTTPVersion.VERSION_1_1); } SetOpt(CURLOPT.PIPEWAIT, true); SetOpt(CURLOPT.SSL_VERIFYHOST, !insecure); SetOpt(CURLOPT.SSL_VERIFYPEER, !insecure); // Ca cert path SetOpt(CURLOPT.CAINFO, s_capath); // Fill request header var requestHeader = new CurlSlist(IntPtr.Zero); if (disableExpect) { requestHeader.Append("Expect:"); } requestHeader.Append($"Content-Type:{contentType}"); if (userHeader != null) { foreach (var entry in userHeader) { requestHeader.Append(entry.Key + ":" + entry.Value); } } SetOpt(CURLOPT.HTTPHEADER, (IntPtr)requestHeader); // Fill request body if (outData != null && outData.Length > 0) { SetOpt(CURLOPT.POSTFIELDS, outData); SetOpt(CURLOPT.POSTFIELDSIZE, outData.Length); } // Handle response header responseHeaderStream = new MemoryStream(); SetOpt(CURLOPT.HEADERFUNCTION, (Delegates.HeaderFunction)HeaderFunction); SetOpt(CURLOPT.HEADERDATA, (IntPtr)thisHandle); bool rangeRequest = rangeStart > 0 || rangeEnd > 0; if (rangeRequest) { if (rangeEnd == 0) { SetOpt(CURLOPT.RANGE, $"{rangeStart}-"); } else { SetOpt(CURLOPT.RANGE, $"{rangeStart}-{rangeEnd}"); } } else { SetOpt(CURLOPT.RANGE, IntPtr.Zero); } // Handle response body recievedDataLength = 0; if (string.IsNullOrEmpty(outputPath)) { responseBodyStream = new MemoryStream(); } else { var dir = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } responseBodyStream = new FileStream(outputPath, rangeRequest ? FileMode.Append : FileMode.OpenOrCreate); } SetOpt(CURLOPT.WRITEFUNCTION, (Delegates.WriteFunction)WriteFunction); SetOpt(CURLOPT.WRITEDATA, (IntPtr)thisHandle); // Debug if (debug) { outHeader = null; SetOpt(CURLOPT.VERBOSE, true); SetOpt(CURLOPT.DEBUGFUNCTION, DebugFunction); SetOpt(CURLOPT.DEBUGDATA, (IntPtr)thisHandle); } else { SetOpt(CURLOPT.VERBOSE, false); SetOpt(CURLOPT.DEBUGFUNCTION, IntPtr.Zero); SetOpt(CURLOPT.DEBUGDATA, IntPtr.Zero); } if (progressCallback != null) { SetOpt(CURLOPT.NOPROGRESS, false); SetOpt(CURLOPT.XFERINFOFUNCTION, ProgressFunction); SetOpt(CURLOPT.XFERINFODATA, (IntPtr)thisHandle); } else { SetOpt(CURLOPT.NOPROGRESS, true); SetOpt(CURLOPT.XFERINFOFUNCTION, IntPtr.Zero); SetOpt(CURLOPT.XFERINFODATA, IntPtr.Zero); } // Timeout SetOpt(CURLOPT.CONNECTTIMEOUT_MS, connectionTimeout); SetOpt(CURLOPT.TIMEOUT_MS, timeout); SetOpt(CURLOPT.LOW_SPEED_LIMIT, lowSpeedLimit); SetOpt(CURLOPT.LOW_SPEED_TIME, lowSpeedTimeout); // Speed limitation SetOpt(CURLOPT.MAX_SEND_SPEED_LARGE, outSpeedLimit); SetOpt(CURLOPT.MAX_RECV_SPEED_LARGE, inSpeedLimit); } catch (Exception e) { CurlLog.LogError("Unexpected exception: " + e); } }
private void Prepare() { try { status = 0; message = null; thisHandle = GCHandle.Alloc(this); SetOpt(CURLOPT.URL, uri.AbsoluteUri); SetOpt(CURLOPT.CUSTOMREQUEST, method); SetOpt(CURLOPT.HTTP_VERSION, (long)HTTPVersion.VERSION_2TLS); SetOpt(CURLOPT.PIPEWAIT, true); if (insecure) { SetOpt(CURLOPT.SSL_VERIFYHOST, false); SetOpt(CURLOPT.SSL_VERIFYPEER, false); } // Ca cert path SetOpt(CURLOPT.CAINFO, s_capath); // Fill request header var requestHeader = new CurlSlist(IntPtr.Zero); requestHeader.Append($"Content-Type:{contentType}"); if (userHeader != null) { foreach (var entry in userHeader) { requestHeader.Append(entry.Key + ":" + entry.Value); } } SetOpt(CURLOPT.HTTPHEADER, (IntPtr)requestHeader); // Fill request body if (outData != null && outData.Length > 0) { SetOpt(CURLOPT.POSTFIELDS, outData); SetOpt(CURLOPT.POSTFIELDSIZE, outData.Length); } // Handle response header responseHeaderStream = new MemoryStream(); SetOpt(CURLOPT.HEADERFUNCTION, (Delegates.HeaderFunction)HeaderFunction); SetOpt(CURLOPT.HEADERDATA, (IntPtr)thisHandle); // Handle response body recievedDataLength = 0; if (string.IsNullOrEmpty(outputPath)) { responseBodyStream = new MemoryStream(); } else { var dir = Path.GetDirectoryName(outputPath); if (!string.IsNullOrEmpty(dir) && !Directory.Exists(dir)) { Directory.CreateDirectory(dir); } responseBodyStream = new FileStream(outputPath, FileMode.OpenOrCreate); } SetOpt(CURLOPT.WRITEFUNCTION, (Delegates.WriteFunction)WriteFunction); SetOpt(CURLOPT.WRITEDATA, (IntPtr)thisHandle); // Debug if (debug) { outHeader = null; SetOpt(CURLOPT.VERBOSE, true); SetOpt(CURLOPT.DEBUGFUNCTION, DebugFunction); SetOpt(CURLOPT.DEBUGDATA, (IntPtr)thisHandle); } // Timeout SetOpt(CURLOPT.CONNECTTIMEOUT_MS, connectionTimeout); SetOpt(CURLOPT.TIMEOUT_MS, timeout); SetOpt(CURLOPT.LOW_SPEED_LIMIT, lowSpeedLimit); SetOpt(CURLOPT.LOW_SPEED_TIME, lowSpeedTimeout); // Speed limitation SetOpt(CURLOPT.MAX_SEND_SPEED_LARGE, outSpeedLimit); SetOpt(CURLOPT.MAX_RECV_SPEED_LARGE, inSpeedLimit); } catch (Exception e) { CurlLog.LogError("Unexpected exception: " + e); } }