Пример #1
0
        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);
        }
Пример #2
0
 private void Awake()
 {
     if (CurlLog.Assert(instance == null, "Only one CurlMultiUpdater instance is allowed"))
     {
         instance = this;
     }
 }
Пример #3
0
 private void Awake()
 {
     CurlLog.Assert(instance == null, "Only one CurlMultiUpdater instance is allowed");
     if (instance == null)
     {
         instance = this;
     }
     defaultMulti = new CurlMulti();
 }
Пример #4
0
        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);
            }
        }
Пример #5
0
        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);
        }
Пример #6
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;
            }
        }
Пример #7
0
        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);
        }
Пример #8
0
        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!");
            }
        }
Пример #9
0
        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);
            }
        }
Пример #10
0
        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);
        }
Пример #11
0
        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);
            }
        }
Пример #12
0
        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);
            }
        }