Вопросы по HTTP API для взаимодействия стороннего софта с CapMonster.

DeimosBlack

Новичок
Регистрация
21.10.2016
Сообщения
5
Благодарностей
0
Баллы
1
Доброго времени суток.
Не нашёл ответа на форуме и в документации и решил написать.

Занимаюсь разработкой клиентского приложения (на с++), в котором необходимо взаимодействовать с CapMonster.

Имеются:
- сервер с CapMonster 2;
- приложение, взаимодействующее с сервером по средством http-запросов;
- сторонний модуль для CM2, установленный и запущенный на капмонстре.

Описание проблемы:
1. Моё приложение правильно работает с AudioSolveMedia-капчей: сервер корректно получает mp3-файл, отправленный через POST form/multi-part и возвращает правильный ответ по GET-запросу.
В данном случае в POST-запрос добавляю поля:

Код:
CapMonsterModule=ZennoLab.AudioSolveMedia
method=post
key={ключ от капмонста}
ParallelMode=true
file=файл(в ASCI)     // так же добавляю http-заголовки Content-Type="audio/mp3" и filename="audio.mp3"
В случае если убрать название файла и ParallelMode - тогда запрос проходит. При изменении других параметров - сервер возвращает ERROR в ответе на POST-запрос, вместо записи вида "OK|{id запущенного процесса на Монстре}". Т.е. если не указывать CapMonsterModule=ZennoLab.AudioSolveMedia, то сервер автоматически не определяет через какой модуль разгадывать капчу.

2. При аналогичном запросе на модуль (который подключен и запущен в КМ на сервере) в ответе на POST-запрос получаю ERROR словно переданы неверные данные (ключ и сам файл проверял ни раз). Файлом изначально является url-encoded data: image/png, base64.

Пробовал 2 варианта:
a. Конвертировать картину в обычный бинарник (в unicode, ASCI, UTF8 ) и отправлять так же, как аудиофайл выше.
b. Не конвертировать/принудительно переконвертировать изображение в base64 url-encoded, посылая следующий запрос:
Код:
CapMonsterModule={НазваниеМодуля}  // название получил следуя инструкции (пкм по модулю в списке подключённых модулей в КМ и выбором пункта "копировать полное имя модуля")
method=base64
key={ключ от капмонста}
ParallelMode=true                  // и без этого поля
file=файл(в base64)                //http-заголовки Content-Type="image/png" [и filename="image.png]"

Итак. Вопросы:
1. Как формировать запрос на сервер так, что бы сервер сам определял тип нужного модуля? (видел в документации, что так можно но не понял как это реализовать).
Пробовал указывать CapMonsterModule ="", вообще не создавать это поле в запросе. Результат таких запросов всегда ERROR и для солвмедиа аудиокапчи, хотя с явным указанием - работает.
2. Как должен выглядеть полностью правильный http POST запрос при загрузке изображения на сервер с CapMonster (какие должны быть заголовки и что должно быть в теле)? (Или: что я делаю не так?)

PS: все запросы производятся на {ip сервера}/in.php
 

slavon

Client
Регистрация
24.06.2016
Сообщения
599
Благодарностей
129
Баллы
43
модуль сам определяется в капмонстре если я не ошибаюсь.
 

DeimosBlack

Новичок
Регистрация
21.10.2016
Сообщения
5
Благодарностей
0
Баллы
1

slavon

Client
Регистрация
24.06.2016
Сообщения
599
Благодарностей
129
Баллы
43

DeimosBlack

Новичок
Регистрация
21.10.2016
Сообщения
5
Благодарностей
0
Баллы
1
CapMonster2.dll думаю что так
CapMonster2.dll - это библиотека, являющаяся частью самого капмонстра. Капмонстр находится на сервере.

У меня же задача стоит сформировать правильный HTTP-запрос для обращения с другого компьютера к КМ, запущенному на сервере.
 

slavon

Client
Регистрация
24.06.2016
Сообщения
599
Благодарностей
129
Баллы
43
CapMonster2.dll - это библиотека, являющаяся частью самого капмонстра. Капмонстр находится на сервере.

У меня же задача стоит сформировать правильный HTTP-запрос для обращения с другого компьютера к КМ, запущенному на сервере.
http://zennolab.com/wiki/ru:addons:capmonster:sm-audio посмотри как тут,у меня тоже кап стоит на серваке а зенки на других серваках.я проста в настройках указываю ip сервака.
 

DeimosBlack

Новичок
Регистрация
21.10.2016
Сообщения
5
Благодарностей
0
Баллы
1
http://zennolab.com/wiki/ru:addons:capmonster:sm-audio посмотри как тут,у меня тоже кап стоит на серваке а зенки на других серваках.я проста в настройках указываю ip сервака.
Уже смотрел. В том примере прямой запрос к модулю
ZennoPoster.CaptchaRecognition("CapMonster2.dll", str, "CapMonsterModule=ZennoLab.AudioSolveMedia&ParallelMode=true");
А обращение к библиотеке дабы это из зенопостера . Я напрямую работую через HTTP.
 

DeimosBlack

Новичок
Регистрация
21.10.2016
Сообщения
5
Благодарностей
0
Баллы
1
2. Как должен выглядеть полностью правильный http POST запрос при загрузке изображения на сервер с CapMonster (какие должны быть заголовки и что должно быть в теле)? (Или: что я делаю не так?)
Вопрос решился.

Про запрос без указания мрдуля - вопрос актуален.
 

ssXXXss

Client
Регистрация
23.12.2014
Сообщения
7 379
Благодарностей
2 041
Баллы
113
ну если не жалко, для новичков будущих выложи как подрубился что бы потом меньше вопросов было о том что есть давно на форуме
 

slavon

Client
Регистрация
24.06.2016
Сообщения
599
Благодарностей
129
Баллы
43

russya

Client
Регистрация
08.07.2014
Сообщения
743
Благодарностей
78
Баллы
28

Adigen

Client
Регистрация
28.07.2014
Сообщения
825
Благодарностей
653
Баллы
93
Уже смотрел. В том примере прямой запрос к модулю
ZennoPoster.CaptchaRecognition("CapMonster2.dll", str, "CapMonsterModule=ZennoLab.AudioSolveMedia&ParallelMode=true");
А обращение к библиотеке дабы это из зенопостера . Я напрямую работую через HTTP.
Запрос без доп параметров, с автоопределением капчи, по возможности.
Код:
POST http://capmonster2.com/in.php HTTP/1.1
User-Agent: TubeCast v1.0
Accept: */*
Accept-Language: ru
Content-Type: multipart/form-data; boundary=8d3fe5455aca93e
Host: 192.168.1.31:88
Content-Length: 6335

--8d3fe5455aca93e
Content-Disposition: form-data; name="method"

post
--8d3fe5455aca93e
Content-Disposition: form-data; name="soft_id"

19
--8d3fe5455aca93e
Content-Disposition: form-data; name="key"

1234567890
--8d3fe5455aca93e
Content-Disposition: form-data; name="file"; filename="Captcha.png"
Content-Type: image/png
.........
--8d3fe5455aca93e--
Только аудио он на автомате вряд ли определит, т.к. есть еще гугл аудио распознавание, а понять какой мп3 к кому относится проблематичнее , чем сортировать картинки по размерам.
 

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

Класс

C#:
 public static class FormUpload
    {
        private static readonly Encoding encoding = Encoding.UTF8;
        public static HttpWebResponse MultipartFormDataPost(string postUrl, string userAgent, Dictionary<string, object> postParameters)
        {
            string formDataBoundary = String.Format("----------{0:N}", Guid.NewGuid());
            string contentType = "multipart/form-data; boundary=" + formDataBoundary;

            byte[] formData = GetMultipartFormData(postParameters, formDataBoundary);

            return PostForm(postUrl, userAgent, contentType, formData);
        }
        private static HttpWebResponse PostForm(string postUrl, string userAgent, string contentType, byte[] formData)
        {
            HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;

            if (request == null)
            {
                throw new NullReferenceException("request is not a http request");
            }

            // Set up the request properties.
            request.Method = "POST";
            request.ContentType = contentType;
            request.UserAgent = userAgent;
            request.CookieContainer = new CookieContainer();
            request.ContentLength = formData.Length;

            // You could add authentication here as well if needed:
            // request.PreAuthenticate = true;
            // request.AuthenticationLevel = System.Net.Security.AuthenticationLevel.MutualAuthRequested;
            // request.Headers.Add("Authorization", "Basic " + Convert.ToBase64String(System.Text.Encoding.Default.GetBytes("username" + ":" + "password")));

            // Send the form data to the request.
            using (Stream requestStream = request.GetRequestStream())
            {
                requestStream.Write(formData, 0, formData.Length);
                requestStream.Close();
            }

            return request.GetResponse() as HttpWebResponse;
        }

        private static byte[] GetMultipartFormData(Dictionary<string, object> postParameters, string boundary)
        {
            Stream formDataStream = new System.IO.MemoryStream();
            bool needsCLRF = false;

            foreach (var param in postParameters)
            {
                // Thanks to feedback from commenters, add a CRLF to allow multiple parameters to be added.
                // Skip it on the first parameter, add it to subsequent parameters.
                if (needsCLRF)
                    formDataStream.Write(encoding.GetBytes("\r\n"), 0, encoding.GetByteCount("\r\n"));

                needsCLRF = true;

                if (param.Value is FileParameter)
                {
                    FileParameter fileToUpload = (FileParameter)param.Value;

                    // Add just the first part of this param, since we will write the file data directly to the Stream
                    string header = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"; filename=\"{2}\"\r\nContent-Type: {3}\r\n\r\n",
                        boundary,
                        param.Key,
                        fileToUpload.FileName ?? param.Key,
                        fileToUpload.ContentType ?? "application/octet-stream");

                    formDataStream.Write(encoding.GetBytes(header), 0, encoding.GetByteCount(header));

                    // Write the file data directly to the Stream, rather than serializing it to a string.
                    formDataStream.Write(fileToUpload.File, 0, fileToUpload.File.Length);
                }
                else
                {
                    string postData = string.Format("--{0}\r\nContent-Disposition: form-data; name=\"{1}\"\r\n\r\n{2}",
                        boundary,
                        param.Key,
                        param.Value);
                    formDataStream.Write(encoding.GetBytes(postData), 0, encoding.GetByteCount(postData));
                }
            }

            // Add the end of the request.  Start with a newline
            string footer = "\r\n--" + boundary + "--\r\n";
            formDataStream.Write(encoding.GetBytes(footer), 0, encoding.GetByteCount(footer));

            // Dump the Stream into a byte[]
            formDataStream.Position = 0;
            byte[] formData = new byte[formDataStream.Length];
            formDataStream.Read(formData, 0, formData.Length);
            formDataStream.Close();

            return formData;
        }

        public class FileParameter
        {
            public byte[] File { get; set; }
            public string FileName { get; set; }
            public string ContentType { get; set; }
            public FileParameter(byte[] file) : this(file, null) { }
            public FileParameter(byte[] file, string filename) : this(file, filename, null) { }
            public FileParameter(byte[] file, string filename, string contenttype)
            {
                File = file;
                FileName = filename;
                ContentType = contenttype;
            }
        }
    }

Так юзать

C#:
string host = "http://127.0.0.3/in.php";
string file = @"img.png";
string mime = "image/png";
string ua = "Bot 1.0";

// Read file data
FileStream fs = new FileStream(file, FileMode.Open, FileAccess.Read);
byte[] data = new byte[fs.Length];
fs.Read(data, 0, data.Length);
fs.Close();

// Generate post objects
Dictionary<string, object> postParameters = new Dictionary<string, object>();
postParameters.Add("CapMonsterModule", "ZennoLab.Bitrix1");
postParameters.Add("file", new FormUpload.FileParameter(data, Path.GetFileName(file), mime));

// Create request and receive response
HttpWebResponse webResponse = FormUpload.MultipartFormDataPost(host, ua, postParameters);

// Process response
StreamReader responseReader = new StreamReader(webResponse.GetResponseStream());
string fullResponse = responseReader.ReadToEnd();
webResponse.Close();
//return fullResponse;

https://ru.wikipedia.org/wiki/Multipart/form-data
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Код:
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
            if (request == null)
            {
                throw new NullReferenceException("request is not a http request");
            }
Зачем создавать объект и потом проверять его на null, если итак ясно, что он будет не null?
В моем понимании правильный код будет такой:
Код:
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl);
а тут using автоматически закроет поток и close не надо вызывать:
Код:
using (Stream requestStream = request.GetRequestStream())
{
       requestStream.Write(formData, 0, formData.Length);
       requestStream.Close();
}
 
Последнее редактирование:

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

А ты проверь его в ситуации когда сервак ответит 4хх или 5хх кодом)

ревьювер))
 
  • Спасибо
Реакции: Adigen

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
А ты проверь его в ситуации когда сервак ответит 4хх или 5хх кодом)

ревьювер))
Так для этого есть блок try-catch и обернуть им надо запрос к серверу, а не создание объекта
 

Adigen

Client
Регистрация
28.07.2014
Сообщения
825
Благодарностей
653
Баллы
93
Так для этого есть блок try-catch и обернуть им надо запрос к серверу, а не создание объекта
Моя твоя не понимать.
Судя по вашим постам, Вы очень поверхностно знакомы с программированием, в частности с С#, но постоянно пытаетесь из себя строить гуру, это какая-то новая модная фишка ?
 
  • Спасибо
Реакции: doc

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

Так для этого есть блок try-catch и обернуть им надо запрос к серверу, а не создание объекта
ну да) чето типа
Код:
        try
        {
            return (HttpWebResponse)req.GetResponse();
        }
        catch (WebException we)
        {
            var resp = we.Response as HttpWebResponse;
            if (resp == null)
                throw;
            return resp;
        }
просто это копипаста перваа из гугла по запросу C# multipart/form-data ))

Моя твоя не понимать.
Судя по вашим постам, Вы очень поверхностно знакомы с программированием, в частности с С#, но постоянно пытаетесь из себя строить гуру, это какая-то новая модная фишка ?
ну да) тут мало кодеров имеющих девелоперские сертификаты MS)
любители кодеры и любители ревьюверы)

и все это оффтоп для сабжа, тс пишет на крестах)
а ему шарп суют)

хотя проще дотпиком открыть CapMonster2.dll и дернуть реализацию от разрабов)
 
Последнее редактирование:
  • Спасибо
Реакции: Adigen

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Моя твоя не понимать.
Судя по вашим постам, Вы очень поверхностно знакомы с программированием, в частности с С#, но постоянно пытаетесь из себя строить гуру, это какая-то новая модная фишка ?
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl);
Покажи мне где тут null объект создается.
Или ты может хочешь сказать, что ты сами веб запросы строишь без обработки исключений?
ну да) чето типа
Код:
        try
        {
            return (HttpWebResponse)req.GetResponse();
        }
        catch (WebException we)
        {
            var resp = we.Response as HttpWebResponse;
            if (resp == null)
                throw;
            return resp;
        }
просто это копипаста перваа из гугла по запросу C# multipart/form-data ))
Я не про момент запроса написал, а про создание объекта HttpWebResponse и потом сразу же проверку на null. С самим запросом итак понятно, что его в любом случае надо оборачивать в блок try catch
P.S. про копипаст итак было понятно, исходя из комментариев к коду
 
Последнее редактирование:

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

HttpWebRequest request = (HttpWebRequest)WebRequest.Create(postUrl);
Покажи мне где тут null объект создается.
Или ты может хочешь сказать, что ты сами веб запросы строишь без обработки исключений?

Я не про момент запроса написал, а про создание объекта HttpWebResponse и потом сразу же проверку на null. С самим запросом итак понятно, что его в любом случае надо оборачивать в блок try catch
ключевой момент тут
WebRequest.... as HttpWebRequest;
тошо у HttpWebRequest нет возвращаемого типа, поэтому и чекаем на null)

понимаю тебя, ломает мозг это, но так прикольнулись архитекторы дотнета, в частности те кто пилил этот класс)) это с этим классом такая шляпа)
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
ключевой момент тут
WebRequest.... as HttpWebRequest;
тошо у HttpWebRequest нет возвращаемого типа, поэтому и чекаем на null)
Этой строчкой мы вообще никак не получим null объект, так как мы можем WebRequest привести к типу HttpWebRequest.
Можно получить исключение, если сделать так (но так никто не делает):
Код:
WebRequest wr;
HttpWebRequest request = (HttpWebRequest)wr;
P.S. даже если пробежаться по примерам из поисковика, то так (проверку на null) никто не делает, кроме тех, кто вообще ничего не понимает в c#.
 
Последнее редактирование:

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

ну я даже хз тогда кто мсдн доки набирает
https://msdn.microsoft.com/ru-ru/library/system.net.httpwebrequest.abort(v=vs.110).aspx


Код:
private static void TimeoutCallback(object state, bool timedOut) {
      if (timedOut) {
          HttpWebRequest request = state as HttpWebRequest;
          if (request != null) {
              request.Abort();
          }
      }
  }
че эт они вдруг чекают на налл перед вызовом аборта)

вот еще
https://msdn.microsoft.com/ru-ru/library/hh221581.aspx



Код:
HttpWebRequest request = null;
request = WebRequest.Create("http://site.com") as HttpWebRequest;
это все нужно для целостности данных.
ноги растут отсюда
https://msdn.microsoft.com/ru-ru/library/system.net.webexception.status(v=vs.110).aspx
 
Последнее редактирование:

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

Во на мсдн пояснения есть в комментариях.
все оказывается разжевано че так чекать на null нужно )

https://msdn.microsoft.com/ru-ru/library/system.net.httpwebrequest(v=vs.110).aspx
https://msdn.microsoft.com/ru-ru/library/system.net.webexception.response(v=vs.110).aspx


Значение свойства
Type: System.Net.WebResponse
Если ответ доступен из Интернет-ресурса, WebResponse экземпляр, содержащий отклик из Интернет-ресурса; в противном случае — null.

кусок из класса того
Код:
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
            if (request == null)
            {
                throw new NullReferenceException("request is not a http request");
            }
После вызова метода Create мы чекаем request. Он будет null в случае 4хх и 5хх ответов.


Запудрил мне мозг с обьектом своим, когда мы сразу стат. метод Create дергаем)
Аминь)


п.с. тс зайдет охереет че мы тут развели, у него кресты)
 

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Во на мсдн пояснения есть в комментариях.
все оказывается разжевано че так чекать на null нужно )

https://msdn.microsoft.com/ru-ru/library/system.net.httpwebrequest(v=vs.110).aspx
https://msdn.microsoft.com/ru-ru/library/system.net.webexception.response(v=vs.110).aspx





кусок из класса того
Код:
HttpWebRequest request = WebRequest.Create(postUrl) as HttpWebRequest;
            if (request == null)
            {
                throw new NullReferenceException("request is not a http request");
            }
После вызова метода Create мы чекаем request. Он будет null в случае 4хх и 5хх ответов.


Запудрил мне мозг с обьектом своим, когда мы сразу стат. метод Create дергаем)
Аминь)


п.с. тс зайдет охереет че мы тут развели, у него кресты)
Самих запросов к сайту этот метод никаких не делает, максимум он может через DNS узнать о наличии соответствия адреса в интернете какому-либо ip, но опять же про этот механизм не уверен. В приведенных майками примерах тоже не нашел проверку на null после создания объекта HttpWebRequest, например тут:

Код:
Uri myUri =new Uri("http://www.contoso.com"); 
WebRequest myWebRequest= WebRequest.Create(myUri);
WebResponse myWebResponse= myWebRequest.GetResponse();
В этом примере они не проверяют на null объект, а если он не может стать null при вызове метода Create, следовательно мы можем его привести к типу HttpWebRequest и потом не производить проверку на NullReferenseException.
В том-то и дело, что WebResponse как раз и может выдать ошибку, а WebRequest - нет.
P.S. да уж, ТС реально охренеет от написанного тут
 

7make

Client
Регистрация
25.06.2011
Сообщения
1 547
Благодарностей
1 311
Баллы
113

Обращаем Ваше внимание на то, что данный пользователь заблокирован.
Не рекомендуем проводить с 7make какие-либо сделки.

amyboose

Client
Регистрация
21.04.2016
Сообщения
2 312
Благодарностей
1 191
Баллы
113
Таки все правильно, но это WebResponse отдает ошибку, а WebRequest только создает объект и от него нет ошибки. Я сам раньше путался в них, потом просто запомнил, что по-английски слово response - ответ, а request - требование, запрос.
Все равно же не твой код, так что можешь не отстаивать криворукость его создателя.
P.S. я бы сам без подсказок с инета не написал бы запрос multipart для HttpClient, так как практика почти нулевая в c#, но теорию учу постоянно.
 

Кто просматривает тему: (Всего: 4, Пользователи: 0, Гости: 4)