Страницы

Поиск по вопросам

Показаны сообщения с ярлыком http. Показать все сообщения
Показаны сообщения с ярлыком http. Показать все сообщения

суббота, 11 апреля 2020 г.

Возникновение сигнала SIGPIPE (ошибка EPIPE) при обращении из браузера Android устройства

#cpp #android #сокет #http #tcp_ip

                    
Написал демон на С++ (Линукс). Он слушает запросы от устройства на Android. 

Причем сделал универсально: в браузере на Android в адресной строке указывается IP-адрес/сайт
(на котором слушает демон), и сам демон посылает в ответ файл, который сохраняется
в браузере.

Использую неблокирующие сокеты, TCP и т.д.

Спустя некоторое время после начала отправки файла приходит ошибка EPIPE (errno =
32 - Broken pipe). После этой ошибки я закрываю сокет.

Не знаю как будет работать на других Android телефонах, но мой делает повторный запрос
и скачивает файл со второго раза без ошибки EPIPE. Боюсь, что на других телефонах файл
просто не скачается.

Если я проделываю то же самое со своего компьютера, то никаких ошибок EPIPE не возникает.

Хотелось бы разобраться почему так происходит.
    


Ответы

Ответ 1



Ошибка EPIPE возвращается обычно в том случае, если данный сокет никем не читается, тоесть нет ни одного процесса, имеющего открытый на чтение дескриптор, связанный с этим сокетом. Возможна ситуация, что Ваш клиент на Андроид по каким-то причинам закрыл дескриптор на чтение, связанный с этим сокетом, тогда, по идее, Вы должны были бы в демоне получить сигнал SIGPIPE и как-то обработать эту ситуацию. Если же вы игнорируете SIGPIPE, то вызов write() обязан вернуть вам EPIPE.

Ответ 2



Разобрался... Потратил кучу времени, чтобы выяснить - просто так на моём китайском телефоне (хотя вроде хуавей хвалят) работает браузер... в нете попадается информация, что стандартный загрузчик на Андроиде (особенно ниже 3.х) с ошибками скачивает файлы, и предлагается установить альтернативный браузер со встроенным менеджером загрузок, может Вам тоже этот подход попробовать? – margosh

Ответ 3



Эта ошибка возникает на всех линуксах, при работе с сокетами. Лечится вызовом signal(SIGPIPE, SIG_IGN);

Post запрос покороче

#net #http

                    
Как сделать POST запрос с минимумом писанины? Интересует urlencoded и multipart.
Вроде такого:

http.PostAsync("http://ya.ru", new PostData() {
    {"1", "2"},
    {"3", "4"},

});

    


Ответы

Ответ 1



new WebClient().UploadValues("http://ya.ru", new NameValueCollection() { {"1", "2"}, {"3", "4"} });

четверг, 9 апреля 2020 г.

Как получить содержимое страницы, которая грузится через AJAX?

#php #ajax #angularjs #http #парсер

                    
Получить содержимое страницы на PHP.
Раньше я делал это достаточно легко через file_get_contents( $url ). Но на одном
сайте список товаров грузится ajax-om, точнее ангуляром.
    То есть если открыть такую страницу в браузере, у вас будет крутиться лоадер
и через некоторе время появятся товары.

Функция file_get_contents( $url ) получает сырой код, то есть типа

{{tovari.name}}
Как получить обработанное( загруженное ) содержимое страницы?


Ответы

Ответ 1



Попробуйте подключиться через curl к нужной странице, должно сработать, например: $curl = curl_init(); curl_setopt($curl, CURLOPT_URL, $url); curl_setopt($curl, CURLOPT_HEADER, false); curl_setopt($curl, CURLOPT_FAILONERROR, 1); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false); curl_setopt($curl, CURLOPT_POST, false); curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($curl) curl_close($curl);

Ответ 2



Вам может помочь phantomjs. Через метод evaluate вы получите контекст загруженной страницы, а дальше можете либо качать всю страницу, либо весь арсенал JS селекторов у вас в руках. Пример взят с офф. сайта: var webPage = require('webpage'); var page = webPage.create(); page.open('http://m.bing.com', function(status) { var title = page.evaluate(function() { return document.title; }); console.log(title); phantom.exit(); });

Ответ 3



С помощью библиотеки CURL это возможно. Недавно сайт парсил где все на ajax и с библиотекой jQuery. Так если парсишь с помощью curl и потом выводим в браузер, то будет все криво, потому-что клиент в данный момент CURL(сервер), а не Вы. Кроссдоменный запрос не прокатит поэтому нужно взять к примеру библиотеку Simple HTMLDOM $curl = curl_init(); curl_setopt($curl, CURLOPT_FAILONERROR, 1); curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1); // allow redirects curl_setopt($curl, CURLOPT_TIMEOUT, 10); // times out after 4s curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); // return into a variable curl_setopt($curl, CURLOPT_URL, "https://ya.ru/"); curl_setopt($curl, CURLOPT_USERAGENT, "Mozilla/5.0 (Windows; U; Windows NT 5.1; ru; rv:1.9.1.5) Gecko/20091102 Firefox/3.5.5 GTB6"); curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false); $data = curl_exec($curl); Выводить $data не нужно. Всё, ваш клиент (сервер) получил страницу. Теперь скачиваем http://simplehtmldom.sourceforge.net/ И есть инструкция например здесь http://zubuntu.ru/php-simple-html-dom-parser/ То есть нам нужно продолжить так: $html=str_get_html($data); $result=$html->find(div.spisok span); //получаем массив Дальше его перебираем. foreach ($result as $one){ echo $one; //можем уже выводить то, что нашли } По такому принципу ищем данные, перебираем их. Важно точно определить "координаты" данных.

Ответ 4



Ну тут же все тоже самое загружаете инструмент разработчика , в любом браузере . В хроме и ему подобных (опера , яндекс , рамблер итд) он встроеный в мозиле firebug смотрите что грузится у вас после загрузки страницы , берете этот url подставляете свои параметры и тем же file_get_contents качаете контент

Ответ 5



В хроме я использую расширение https://chrome.google.com/webstore/detail/quick-source-viewer/cfmcghennfbpmhemnnfjhkdmnbidpanb?utm_source=chrome-app-launcher-info-dialog После загрузки страницы и отработки скриптов можно посмотреть результат со всеми изменениями.

Подключение к базе данных. Когда создавать и сколько ему жить в веб-приложении?

#база_данных #aspnet #aspnet_mvc #http #веб_программирование

                    
Когда создавать подключение к базе данных?


На каждый запрос к базе
На каждый HTTP-запрос
Глобально в рамках домена - от старта приложения до его смерти


Первые два позволяют локализовать ошибки (обрыв связи с базой покрашит минимум запросов),
обеспечит многопоточную обработку запросов к базе(?) на стороне веб-сервера.

Третий - сократит оверхед на подключениях, особенно если БД вынесена на отдельный
сервер, но лишится плюсов первых двух.

Так что же лучше и в каких случаях стоит применять? Интересно это как по поводу чистого
ADO.NET, так и EF (если под "подключением" мы будем понимать наследника DbContext).
По поводу последнего в туториалах в интернете рассуждают о разнице между п.1 и п.2,
но не п.3. Почему?
    


Ответы

Ответ 1



Если у программиста возникает такой вопрос, то ему стоит использовать Entity Framework, по тому, что в данном случае фреймворк окажется умнее программиста, который своими попытками оптимизации с наибольшей вероятностью сделает только хуже. Во первых, DbContext, это Unit of Work(как и ISession в NHibernate) Наличие одного DbContext для всего приложения - плохая идея. Единственная ситуация, где это имеет смысл, когда у вас есть однопоточное приложение и база данных, которая используется исключительно этим экземпляром приложения. DbContext не поточно-безопасный, а так же DbContext кэширует данные, по этому вы быстро получите не актуальный кэш. Все это приведет к различным проблемам, когда несколько пользователей/приложений будут работать с этой базой данных одновременно. По этому если у вас не вышеописанная ситуация, то вам лучше инжектить DbContext в каждую задачу. Создавать же контекст на каждый запрос не лучший вариант с точки зрения производительности. Во первых при подключении происходит аутентификация и авторизация, во вторых вы теряете преимущества благодаря кешированию. Другими словами, вам нужно выделять DbContext на каждую бизнес-задачу.

четверг, 19 марта 2020 г.

Как послать JSON в теле HTTP-ответа?

#c_sharp #openlayers #json #http #ajax


Отдается JSON так:

HttpListener listener = new HttpListener();
listener.Prefixes.Add(new Uri("http://localhost:8181"));
listener.Start();
while (isListening) {
  HttpListenerContext context = listener.GetContext();
  HttpListenerRequest request = context.Request;
  HttpListenerResponse response = context.Response;
  //...
  MemoryStream ms = (GeoJsonDeserialize.SerializeGeoJson(ObjToJson) as MemoryStream);
  byte[] buffer = ms.ToArray();
  response.StatusCode = (int)HttpStatusCode.OK;
  response.KeepAlive = false;
  response.ContentType = "application/json";
  response.ContentEncoding = System.Text.UTF8Encoding.UTF8;
  response.ContentLength64 = buffer.Length;
  response.AddHeader("Cache-Control", "private, max-age=0");
  Stream output = response.OutputStream;
  output.Write(buffer, 0, buffer.Length);
  ms = new MemoryStream();
  ms.Write(buffer, 0, buffer.Length);
  buffer = ms.ToArray();
  output.Close();
}

В другой проге на C# я запрашиваю так:

WebRequest webRequest = WebRequest.Create("http://localhost:8181");
WebResponse webResponse = webRequest.GetResponse();
StreamReader sr = new StreamReader(webResponse.GetResponseStream());
String str = sr.ReadToEnd();

и вижу переданный текст (JSON).
Но вот беда - ни Ajax не видит тело ответа (выдает ошибку), ни OpenLayers который
по GeoJSON должен показать точки на карте.

OpenLayers запрашивает данные (за основу взят пример OpenLayersRotationExample):
vectors = new OpenLayers.Layer.Vector( "Simple Geometry", {
  protocol: new OpenLayers.Protocol.HTTP({
    url: "http://localhost:8181",   format: new OpenLayers.Format.GeoJSON()
  }),
  strategies: [new OpenLayers.Strategy.Fixed()]
});
map.addLayers([vectors]);

Объект в JSON (GeoJSON) выглядит так:

{"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[-108.04,44.68]},"properties":{"course":184.7}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-111.04,45.68]},"properties":{"course":44.1}}]}

Специально пробовал текст передаваемого JSON загрузить в OL непосредственно в JavaScript:

var featurecollection = {"type":"FeatureCollection","features":[{"type":"Feature","geometry":{"type":"Point","coordinates":[-111.04,45.68]},"properties":{"course":42.9}},{"type":"Feature","geometry":{"type":"Point","coordinates":[-111.04,45.68]},"properties":{"course":157.5}}]};
var geojson_format = new OpenLayers.Format.GeoJSON();
var vector_layer = new OpenLayers.Layer.Vector("Simple 1", {
styleMap: new OpenLayers.StyleMap({
  "default": {
     externalGraphic: "OpenLayersRotationExample_files/marker-gold.png",
         //graphicWidth: 17,
         graphicHeight: 20,
         graphicYOffset: -19,
         rotation: "${course}",
     },
     "select": {
        cursor: "crosshair",
        externalGraphic: "OpenLayersRotationExample_files/marker.png"
     }
  })
}); 
map.addLayer(vector_layer);
vector_layer.addFeatures(geojson_format.read(featurecollection));

И все работает - точки отображаются.
Вывод - я неправильно отдаю JSON.
Подскажите как в ответ на запрос отдать JSON что бы JavaScript его смог принять?    


Ответы

Ответ 1



Поскольку провайдер точек и страница отображающая карту находится в разных доменах, действует Same Orign Policy. В OpenLayers есть OpenLayers.Protocol.Script который использует JSONP для получения данных. По умолчанию callback называется OpenLayers.Protocol.Script.registry.c1. Вам необходимо переделать провайдер соответствующим образом, чтобы он оборачивал результирующий JSON в эту функцию.

воскресенье, 8 марта 2020 г.

WCF служба, wsDualHttpBinding и 80 порт

#c_sharp #net #http #wcf


При подключении к WCF службе вылетает exception, хотя в app.config конфиг явно указан
не 80 порт:


  An unhandled exception of type 'System.ServiceModel.AddressAlreadyInUseException'
occurred in
  System.ServiceModel.dll
  
  Additional information: HTTP could not register URL
  http://+:80/Temporary_Listen_Addresses/c3e45f68-abf2-4847-95a6-cfd3f512fc54/
  because TCP port 80 is being used by another application.


Самое странное, что на одном ПК вылетает exception, а на другом нет. В чем может
быть проблема?

app.config клиента :



     
        
    
    
        
            
                
            
        
        
            
            
        
    



app.config сервер:


  
    
  
  
    
      
        
        
        
          
            
          
        
      
    
    
      
        
          
        
      
    
  


    


Ответы

Ответ 1



Вы используете wsDualHttpBinding. В этом режиме клиент прослушивает некоторый адрес, где ожидает ответы от сервера. И вот этот-то адрес, который в конфиге вы не задавали, и находится на 80м порту по умолчанию! Используйте атрибут clientBaseAddress для указания обратного адреса на клиенте: Либо используйте другие способы соединения. Так, netTcpBinding - и без обратного адреса умеет передавать сообщения в обе стороны. Еще где-то в WCF есть поддержка веб-сокетов, но я не помню где. Теперь почему может быть занят 80й порт на некоторых компьютерах. Скорее всего, это Skype, который использует этот порт по умолчанию: Но, конечно же, не следует отбрасывать и вариант обычного веб-сервера, Apache, Nginx или Tomcat. А вот IIS с WCF "дружат", поскольку используют один и тот же HTTP.SYS.

Как перехватить кнопку “назад” браузера?

#javascript #http #button #кэширование #браузер


На странице используется JavaScript, пользователь может изменить вид страницы. При
переходе по ссылке на другую страницу того же сайта и затем нажатии на кнопку "Назад"
браузера, теряются сделанные пользователем изменения на первой странице.

Как перехватить событие возврата на страницу, чтобы можно было ее обновить?
    


Ответы

Ответ 1



В комментариях верно написали, что ответ кроется не в перехвате события "назад" у браузера, а сохранении состояния страницы Например, пользователь может изменить тему страницы. Что бы при возвращении на эту страницу, была выбрана нужная тема, сохраним ее в localStorage const savePageState = (name, state) => { localStorage[name] = state; } const loadPageState = (name) => { return localStorage[name]; } Дальше, при нужных вам событиях, вы просто сохраняете в localStorage нужные вам данные, а при загрузке страницы (onload событие, например) выгружаете нужные данные и используете их

Ответ 2



Раз пользователь может изменить вид страницы, значит, работает javascript. В нем надо при обработке пользовательских действий подменить последний элемент в истории браузера, чтобы возврат происходил уже на указанную вами страницу (или тот же адрес, но с параметрами). Вот пример. Код скрипта: $('.portfolio_filter').each(function(){ var $this_filter = $(this); $this_filter.on('click', 'a', function(){ var project_type = $(this).data('optionValue').slice(1); var url = window.location.href; if (url.indexOf('?') >= 0) { url = url.slice(0, window.location.href.indexOf('?')); } if (project_type) { url = url + '?type=' + project_type; } // console.log('url: ' + url); window.history.replaceState(null, document.title, url); return false; }); }); При клике не кнопку на странице в историю дописывается url типа http://sws-group.zephyrlab.ru/projects/?type=commercial После просмотра проекта категории commercial возврат идет уже на url с ?type=commercial.

Ответ 3



Перехватить событие возврата на страницу не получилось, задача решена другим способом. Я добавил на стороне сервера в http-заголовок Cache-Control значения no-store, must-revalidate, как написано здесь: https://stackoverflow.com/questions/49547/how-to-control-web-page-caching-across-all-browsers Таким образом, при нажатии "Назад" страница автоматически обновляется браузером вообще без использования дополнительного кода JavaScript. Сделанные пользователем изменения при этом не теряются, т.к. они до этого были сохранены на сервере. При обновлении страницы по F5 также получаем с сервера самое последнее состояние страницы. Если бы состояние хранилось не на сервере, пришлось бы дописать немного JavaScript-кода (для работы с localStorage или куками), но history.replaceState я бы использовать не стал. Вместо хранения состояния (на стороне клиента) в history, гораздо удобнее хранить то же самое состояние в localStorage.

Редирект на 404 страницу

#php #http #редирект #header


В .htaccess прописал:

ErrorDocument 404 /views/error.html


В скрипте отправляю заголовок:

header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404);
exit();


Перенаправление не срабатывает.
Пробовал и так писать:

header('HTTP/1.1 404 Not Found', true, 404);
header('HTTP/1.0 404 Not Found', true, 404);
header('HTTP/1.1 404 Not Found');
header('HTTP/1.0 404 Not Found');


Не срабатывает всё равно. Может что-то дописать нужно ещё?
    


Ответы

Ответ 1



ErrorDocument верно срабатывает, когда реально нет страницы. Передача заголовка лично у меня тоже верно сработала, и в целом должна верно срабатывать, если сервер и php верно настроены. Но при этом во втором пункте apache уже не собирается переадресацию какую-то делать, так как он не видит в этом смысла - ErrorDocument срабатывает именно что на реальное отсутствие страницы или отсутствие правил редиректа для запрошенного адреса, когда же страница просто отдает код 404 - это ее дело. Далее подразумевается, что нужно самому вывести нужное. То есть либо заинклудить целиком страницу, лежащую по пути /views/error.html примерно таким кодом: if (we_have_404) { header($_SERVER['SERVER_PROTOCOL'] . ' 404 Not Found', true, 404); include "/views/error.html"; exit(); } дабы минимизировать повторяющийся код на сайте, либо выводить что-либо свое.

четверг, 5 марта 2020 г.

Какие коды ошибок возвращать в rest?

#java #http #rest


В задании написано вернуть коды ошибок типичные для rest. Какие именно? Какие коды
являются типичными для rest?
    


Ответы

Ответ 1



Типичные для REST это ошибки 200 - успешные 400 - ошибки на стороне клиента 500 - ошибки на стороне сервера

вторник, 25 февраля 2020 г.

За что отвечают мета тег csrf-param и csrf-token?

#теги #html #http #мета


Подскажите, за что отвечают мета тег csrf-param и csrf-token, не могу найти нигде
их описания.    


Ответы

Ответ 1



CodeIgniter: Межсайтовая подделка запросов (Cross-site request forgery, CSRF) Вы можете включить защиту CSRF, открыв ваш application/config/config.php и установив в нем: $config['csrf_protection'] = TRUE; Если вы используете помощник форм, функция form_open() автоматически будет добавлять скрытое поле CSRF в ваши формы.

Ответ 2



CSRF – атаки. (Cross-Site Request Forgery) CSRF расшифровывается как “Cross-Site Request Forgery” (Межсайтовая подделка запроса). Данный тип атак направлен на имитирование запроса пользователя к стороннему сайту. Эта уязвимость достаточно широко распространена из за особенностей архитектуры большинства веб-приложений. А именно из-за того, что многие веб-приложения не чётко определяют - действительно ли запрос сформирован настоящим пользователем.

суббота, 15 февраля 2020 г.

В чем отличие между HTTP методами HEAD и OPTIONS?

#веб_программирование #сеть #http #веб_сервер


В чем отличие между HTTP методами HEAD и OPTIONS? я знаю лишь что в ответ на OPTIONS
сервер должен отдать Allow со списком поддерживаемых методов. Есть ли еще какие либо
концептуальные/технические отличия?
    


Ответы

Ответ 1



У этих запросов разное назначение: HEAD - служит для проверки существования ресурса, он полностью аналогичен GET, но без возврата тела ответа OPTIONS - служит для получения параметров для ресурса или для сервера в целом и при этом сам ресурс ни как не затрагивается (то есть это более дешевая операция по сравнению с HEAD) OPTIONS возвращает параметры в заголовке. Список параметров зависит о ресурса и/или сервера. Обычно это заголовок Allow, который описывает какие методы доступны для ресурса.

Ответ 2



HEAD Данный метод по своей сути похож на GET, но сервер отвечает на запрос одним лишь заголовком. (Отсюда и название метода.) Применяется, например, чтобы узнать, существует ли в сети тот или иной URL и не произошло ли каких-нибудь изменений. OPTIONS Метод представляет запрос информации об опциях соединения, доступных в цепочке запросов/ответов, идентифицируемой запрашиваемым URI (Request-URI). Этот метод позволяет клиенту определять опции и/или требования, связанные с ресурсом, или возможностями сервера, но не производя никаких действий над ресурсом и не инициируя его загрузку.

Ответ 3



Отличие этих методов - в том, что HEAD запрашивает информацию о ресурсе, а OPTIONS запрашивает информацию о методах доступа к ресурсу. Более подробно. Заголовки, возвращаемые методом HEAD, обязаны соответствовать заголовкам, возвращаемым методом GET. При этом, метод HEAD не имеет никакого отношения к методам POST, PUT, DELETE и прочим. В то же время, настройки доступа, возвращаемые методом OPTIONS, имеют отношение сразу ко всем методом ресурса - GET, POST, PUT, DELETE и пр. Если говорить о применении, то метод HEAD может использоваться чтобы получить информацию о странице без скачивания самой страницы. Метод OPTIONS же используется, в основном, механизмом Preflight request в CORS или для обнаружения поддерживаемых сервером фич в WebDAV.

Используется ли во всех браузерах независимо от ОС перевод строки \r\n?

#linux #windows #http #браузер #apple


Добрый день! Наткнулся на информацию, что в разных операционных системах перевод
строки пишется по-разному:

Windows - \r\n

Apple - \r

Linux - \n

Но также где-то писали, что HTTP протокол независимо от системы использует \r\n.

Кому верить?
    


Ответы

Ответ 1



формат заголовков http соответствует спецификации, изложенной в rfc822. согласно секции 3.1.2 rfc822, поле заголовка должно заканчиваться двумя символами — возврат каретки (carriage-return, cr, в ascii — шестнадцатиричное значение 0d) и перевод строки (line-feed, lf, в ascii — шестнадцатиричное значение 0a): Once a field has been unfolded, it may be viewed as being composed of a field-name followed by a colon (":"), followed by a field-body, and terminated by a carriage-return/line-feed. в теле же сообщения (это может быть и html-страница, и вообще всё что угодно, например, просто бинарные данные), конечно, могут встретиться любые символы в любой комбинации.

среда, 12 февраля 2020 г.

libcurl - как парсить HTTP заголовок?

#cpp #http #curl #парсер #веб_сервер


Учусь писать HTTP веб-сервер. Сам сервер есть. Запускаю сервак, посылаю HTTP-запрос
curl -D dumpbin 127.0.0.1:2000. На сервере сохраняю запрос в строковую переменную.
Теперь (и я не знаю, как это сделать) мне надо распарсить весь полученный запрос, составить
ответ и отправить обратно. С отправкой я справлюсь, а вот с парсингом и с составлением
ответа возникли проблемы. 
Сказали, что следует использовать libcurl, но я не понимаю, как им можно парсить
готовые строки и можно ли.
Помогите, пожалуйста, примером такого использования этой либы, если он возможен.
Посоветуйте, какие можно использовать библиотеки еще, чтобы решить эту задачу.

//Вид запроса (это то, что вернул мой эхо-сервер при использовании утилиты curl): 

    request = "GET /index.html HTTP/1.1\r\n"
              "Host: 127.0.0.1:5991\r\n"
              "User-Agent: curl/7.47.0\r\n"
              "Accept: */*\r\n"
              "\r\n";

    //Вид ответа (это я прочитал в комментах к заданию на степике):
    answer = "HTTP/1.0 200 OK\r\n"
             "Content-length: %d\r\n"
             "Connection: close\r\n"
             "Content-Type: text/html\r\n"
             "\r\n"
             "%s";


Суть в том, что есть данные, которые разделены \r\n и заканчиваются двойным переводом
каретки и строки \r\n\r\n
    


Ответы

Ответ 1



tl;dr см. конец ответа для реализации парсера заголовков licurl используют, как правило, для написания клиентов, смотрите FAQ: 5.17 Can I write a server with libcurl? No. libcurl offers no functions or building blocks to build any kind of internet protocol server. libcurl is only a client-side library. For server libraries, you need to continue your search elsewhere but there exist many good open source ones out there for most protocols you could possibly want a server for. And there are really good stand-alone ones that have been tested and proven for many years. There's no need for you to reinvent them! В вольном переводе: 5.17 Могу ли я использовать libcurl для написания сервера? Нет. libcurl не предлагает функций или других строительных блоков для создания какого либо IP сервера. libcurl это только клиентская библиотека. Вам нужно продолжить ваши поиски библиотеки для построения сервера. Существует большое количество таких библиотек с открытым исходным кодом для большинства протоколов. Также существует большое кол-во проверенных годами stand-alone приложений. Вам не стоит изобретать их заново. Хотя для построения клиента libcurl действительно очень удобная вещь, как упомянул в своем ответе @Pink Tux. В том числе заголовки вы получаете уже разбитые по одному. Для построения сервера, как один из вариантов, можно использовать mongoose (на c, в виде пары .c/.h, добавляемой к вашему проекту, либо одну из многочисленных c++ оберток). Пример минимального сервера достаточно громоздкий, поэтому приводить здесь не буду. Можно посмотреть здесь. Еще один вариант - библиотека cpp-netlib которая изначально планировалась как часть boost (но потом планы разработчиков поменялись). В простейшем виде http сервер выглядит так: namespace http = boost::network::http; struct handler; typedef http::server http_server; struct handler { void operator() (http_server::request const &request, http_server::response &response) { response = http_server::response::stock_reply( http_server::response::ok, "Hello, world!"); } void log(http_server::string_type const &info) { std::cerr << "ERROR: " << info << '\n'; } }; int main(int arg, char * argv[]) { handler handler_; http_server::options options(handler_); http_server server_( options.address("0.0.0.0") .port("8000")); server_.run(); } Если вам нужно что-то еще более высокоуровневое (с поддержкой шаблонов, json, middlewares), можно взять crow, которая подключается к вашему проекту одним заголовочным файлом. По духу это напоминает Python Flask. Пример сервера: #include "crow_all.h" int main() { crow::SimpleApp app; CROW_ROUTE(app, "/")([](){ return "Hello world"; }); app.port(18080).multithreaded().run(); } Если все-таки интересно самому разобрать заголовки, то можно например таким кодом: std::istringstream rawstream(raw); std::map headers; std::string header; while (std::getline(rawstream, header) && header != "\r") { std::string::size_type index = header.find(':'); if (index != std::string::npos) { headers.insert(std::make_pair( boost::algorithm::trim_copy(header.substr(0, index)), boost::algorithm::trim_copy(header.substr(index + 1)) )); } } В raw типа std::string помещаете строку с вашими заголовками (либо даже целиком запрос клиента), в headers получаете map из имен/значений заголовков. Используете к примеру так: std::cout << headers["Content-Type"] << std::endl; Обратите внимание, что по стандарту имя заголовка может иметь любой регистр. Поэтому CONTENT-TYPE, content-type и Content-Type это все один заголовок, и для удобства можно перед добавлением в map привести имя заголовка в нижний регистр: headers.insert(std::make_pair( boost::algorithm::to_lower_copy(boost::algorithm::trim_copy(header.substr(0, index))), boost::algorithm::trim_copy(header.substr(index + 1)) )); Действующий пример на Ideone.com. P.S. Для тестирования вместо curl можно использовать postman в котором можно задавать заголовки, тело страниц (в том числе json), сохранять наборы запросов и т.д.

Ответ 2



libcurl предоставляет возможность задавать обработчик для разных данных. Например, чтобы "поймать" заголовки ответа, можно воспользоваться следующим подходом: static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { /* * Эта функция будет вызываться на каждый возвращаемый заголовок. */ return nitems * size; } int main() { CURL *curl = curl_easy_init(); if(curl) { curl_easy_setopt(curl, CURLOPT_URL, "http://yahoo.com/"); curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, header_callback); curl_easy_perform(curl); } return 0; } Подробней - см. в документации по libcurl. Кроме того, для C++ есть обёртки, например, curlcpp.

воскресенье, 9 февраля 2020 г.

Как посмотреть по http наличие файла? (node js)

#javascript #nodejs #http #веб_сервер


Как на ноде проверить наличие файла в дерриктории http? Мне не нужно его скачивать,
просматривать, а просто знать - есть он или нет.
По сути мне нужно отправить http запрос например на  урл http://example.org/file.txt
и получить ответ, распарсить и если 404 не наблюдаю то гуд иначе не гуд... 
    


Ответы

Ответ 1



Для определения наличия ресурса можно использовать метод HEAD. В ответ на HEAD запрос не будет возвращаться содержимое файла. При этом потребуется проверить код ответа: 200 - ресурс есть. Вы можете использовать, например, модуль request, который дочтаточно прост и содержит функцию head: const request = require("request"); request.head("http://www.cfcl.com/vlb/Cuute/f/a-few-bricks.txt").on("response", res => { global.console.log(res.statusCode); }); или использовать модуль http самой ноды и функцию request const http = require("http"); const req = http.request( { hostname: "www.cfcl.com", path: "/vlb/Cuute/f/a-few-bricks.txt", method: "HEAD", }, res => { global.console.log(res.statusCode); }, ); req.end();

среда, 5 февраля 2020 г.

Парсинг сайта metanit

#c_sharp #net #парсер #http


Хочу спарсить сайт metanit.com

Стандартными средствами(пример кода https://github.com/extremecodetv/Html-Parser-Tutorial)
не выходит. Просто отдает одну пустую страницу.

Пытался использовать Selenium, но тоже работает через раз, да и способ этот мне не
нравится: ради парсинга целый движок браузера загружать.

Может вы знаете способ лучше? И почему не работает обычный System.Net.Http.HttpClient ?
    


Ответы

Ответ 1



Проверил я данный сайт. Получаете вы не пустую страницу как таковую, а ошибку 403, которая гласит: Access forbidden! You don't have permission to access the requested object. It is either read-protected or not readable by the server. Из за чего это может быть? Хм, ну по сути это происходит по двум причинам: Вам заблокировали доступ на сервер (или часть сервера) Сервер имеет некую защиту от автоматизации, которая обычно бывает: Банальная проверка User-Agent заголовка у запроса. Проверка Cookie. Комплексные защиты (CloudFlare например, где используют и то и то сразу (а то и больше...)). Для начала нам стоит отловить запрос, который мы посылаем при заходе на сервер и по очереди добавлять в наш код все, что необходимо. Лично я всегда использую подобный код для отправки запросов: public async Task SendRequest(string url) { string data; var baseAddress = new Uri("https://metanit.com"); var cookieContainer = new CookieContainer(); using (var handler = new HttpClientHandler { CookieContainer = cookieContainer }) using (var client = new HttpClient(handler) { BaseAddress = baseAddress }) { var result = await client.GetAsync(url); data = await result.Content.ReadAsStringAsync(); } return data; } И так, пробуем по порядку, попробуем задать другой User-Agent. Для этого нам достаточно добавить подобную строку до получения result переменной: client.DefaultRequestHeaders.Add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/64.0.3282.140 Safari/537.36 Edge/17.17120"); И о чудо, сервер открыл нам доступ! Если бы сервер требовал от нас Cookie, то стоило бы добавить что то вроде этого до result: cookieContainer.Add(baseAddress, new Cookie("key", "value")); В общем, экспериментируйте и смотрите что именно отправляет ваш браузер на сервер, тогда будет в разы легче сделать то, что вы хотите.

Ответ 2



Приведу пример с HttpWebRequest код получен, парсить можно чем угодно дальше. using System; using System.IO; using System.Net; using System.Text; using System.Windows.Forms; namespace TestParse { public partial class Form1 : Form { public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { txtLog.Text = Parser("https://metanit.com"); } public static string Parser(string url) { HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); request.Method = "GET"; request.Accept = "application/json"; request.UserAgent = "Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36"; HttpWebResponse response = (HttpWebResponse)request.GetResponse(); StreamReader reader = new StreamReader(response.GetResponseStream()); StringBuilder output = new StringBuilder(); output.Append(reader.ReadToEnd()); response.Close(); return output.ToString(); } } } Раз вы упомянули Selenium приведу пример с использованием WebDriver с возможностью обхода Cloudflare public string GetHtml(string url) { string html = null; try { var driverService = PhantomJSDriverService.CreateDefaultService(); driverService.HideCommandPromptWindow = true; var Driver = new PhantomJSDriver(driverService); Driver.Navigate().GoToUrl(url); while (Driver.PageSource.Contains("setTimeout(function()")) Thread.Sleep(1000); html = Driver.PageSource; Driver.Close(); Driver.Quit(); return html; } catch { } return null; }

понедельник, 3 февраля 2020 г.

Доступность сайта одновременно по HTTP и HTTPS

#http #https


Есть сайт, для него установлен бесплатный сертификат для работы HTTPS.

Можно ли коим-то образом сделать сайт доступным одновременно по HTTP и по HTTPS?
    


Ответы

Ответ 1



Да, просто нужно настроить апач (или другой веб-сервер). HTTP работает на 80 порту, а HTTPS работает на 443-м. В апаче необходимо создать 2 виртуальных хоста, один для 80-го порта, 2-й для 443-го. Для этих виртуальных хостов установить одинаковые настройки (какие вам необходимы), кроме этого, для ВХ на 443-м порту необходимо активировать SSLEngine, чтобы иметь возможность соединяться по HTTPS: SSLEngine on #путь к сертификату. SSLCertificateFile /etc/ssl/certs/ssl-cert-snakeoil.pem #путь к ключу SSLCertificateKeyFile /etc/ssl/private/ssl-cert-snakeoil.key

Ответ 2



Добавлю вариант для nginx (из документации): server { listen 80; listen 443 ssl; server_name www.example.com; ssl_certificate www.example.com.crt; ssl_certificate_key www.example.com.key; ... }

воскресенье, 2 февраля 2020 г.

Заливка большого файла на WEB сервер методом POST python

#python #сервер #http #post


Помогите разобраться в чем проблема.
Хочу залить файл на сервер, использую библиотеку requests.
Маленький файл льется отлично, с большим файлом беда - не уходит.
Код:

import requests
r = requests.get('запорос на урл')
upload_url = r['урл сервера']
file = {'video_file': ('1.mp4', open('S:/1.mp4', 'rb'))}
r2 = requests.post(upload_url, files=file)


ответ питона 

Traceback (most recent call last):
  File "S:/charm/projects/2.py", line 13, in 
    r2 = requests.post(upload_url, files=file)
  File "S:\charm\projects\venv\lib\site-packages\requests\api.py", line 112, in post
    return request('post', url, data=data, json=json, **kwargs)
  File "S:\charm\projects\venv\lib\site-packages\requests\api.py", line 58, in request
    return session.request(method=method, url=url, **kwargs)
  File "S:\charm\projects\venv\lib\site-packages\requests\sessions.py", line 494,
in request
    prep = self.prepare_request(req)
  File "S:\charm\projects\venv\lib\site-packages\requests\sessions.py", line 437,
in prepare_request
    hooks=merge_hooks(request.hooks, self.hooks),
  File "S:\charm\projects\venv\lib\site-packages\requests\models.py", line 308, in
prepare
    self.prepare_body(data, files, json)
  File "S:\charm\projects\venv\lib\site-packages\requests\models.py", line 496, in
prepare_body
    (body, content_type) = self._encode_files(files, data)
  File "S:\charm\projects\venv\lib\site-packages\requests\models.py", line 159, in
_encode_files
    fdata = fp.read()
MemoryError


Повторю, маленькие файлы грузит отлично.
Что не так?
    


Ответы

Ответ 1



Попробуйте использовать requests-toolbelt: # pip install requests-toolbelt from requests_toolbelt import MultipartEncoder # pip install requests import requests upload_file = open('S:/1.mp4', 'rb') payload = MultipartEncoder({'1.mp4': upload_file}) rs = requests.post('', data=payload , headers={'Content-Type': payload.content_type}) print(rs)

Ответ 2



Если сервер может напрямую файл принимать (в http message-body), то достаточно файл как data передать: import requests with open('1.mp4', 'rb') as file: requests.post(url, data=file)

Ответ 3



Чтобы послать файл на сервер, используя multipart/form-data Сontent-Type как
html-элементом в браузере делают, можно pycurl использовать: import pycurl c = pycurl.Curl() c.setopt(c.URL, url) c.setopt(c.HTTPPOST, [('file', (c.FORM_FILE, filename))]) c.perform() c.close()

суббота, 1 февраля 2020 г.

Поддерживают ли новые версии PHP HTTP методы нативно?

#php #http


Поддерживают ли новые версии PHP HTTP методы нативно?
    


Ответы

Ответ 1



PHP - это язык, HTTP - это протокол. Веб-сервер через FastCGI отдает то, что пришло из браузера, в PHP. PHP разбирает запрос (он в виде текста), инициализирует $_SERVER, $_GET, $_REQUEST и прочее. Какой метод был вызван - можно посмотреть через $_SERVER['REQUEST_METHOD']. Более PHP о HTTP методах не знает ничего. Более того, в запросе можно отправить вообще любое название в качестве HTTP метода. Также есть ответ на enSO

воскресенье, 26 января 2020 г.

Невидимые параметры в fiddler или почему мой запрос не проходит? [закрыт]

#c_sharp #http #get


        
             
                
                    
                        
                            Закрыт. Этот вопрос не по теме. Ответы на него в данный
момент не принимаются.
                            
                        
                    
                
                            
                                
                
                        
                            
                        
                    
                        
                            Хотите улучшить этот вопрос? Переформулируйте вопрос,
чтобы он соответствовал тематике «Stack Overflow на русском».
                        
                        Закрыт 4 года назад.
                                                                                
           
                
        
Проблема для меня магическая. Задача - пройти авторизацию на сайте ru.wix.com. Для
этого нужно получить определенные куки, отправив определенный запрос. Работаю из приложения
на c# с помощью библиотеки xNet. Так вот, проблема в том, что делая запрос из приложения(как
через fiddler, так и напрямую), мой запрос не проходит, куки не выдаются и загружаются
другие данные. 
Но стоит мне повторить тот же самый запрос(!) из fiddler'а(хот-кей "R" или "Reissue
Requests"), как он спокойно проходит, выдаются куки и загружается нужный контент. Этому
есть какое-то объяснение?

UPD: Заметил, что если повторять запрос с частотой 1сек - то проходит ровно на 5й
раз, если с частотой в 2 - то где-то на третий. При этом одиночная пауза в 3-4-5-6сек
не подходит, все равно нужно повторять. В браузере и через fiddler проходит все с 1го раза.

UPD2:: Попробовал через WebRequest - тоже самое. При этом, если формировать те же
самые запросы от начала и до конца с помощью Composer fiddler'a, проходит на ура. Очень
прошу помощи.
    


Ответы

Ответ 1



Проверь редиректы. .net'овский запрос по умолчанию сам обрабатывает редирект, поэтому если куки были выставлены в ответе, где делается редирект, то ты их пропустил и получил уже следующую страницу (запрошенную без этих кук). Попробуй отключить автоматическую обработку редиректа, достать всё необходимое из ответа и выполнить дальнейшие действия вручную. Кстати, там, где я действовал таким образом, я вообще не запрашивал страницу, на которую сделан редирект - я просто вытаскивал куки и слал следующий нужный мне запрос.

Ответ 2



На сколько понял, вы проксируете запрос через фидлер, и он отрабатывает успешно. В таком случае, скорее всего, библиотека которой вы пользуетесь, не обрабатывает ответ сервера коректно.

Как закачать с HTTP большой файл?

#http #android #java


Пишу свое первое приложение, по этому прошу сильно не ругать...

Возможно ли скачать файл из Интернета без помощи BufferedInputStream?

Проблема вся в том, что при скачивании файла размером до 50мб все в порядке, но если
файл больше, получаю исключение с ошибкой о переполнении кучи.


  12-18 18:20:26.846: I/dalvikvm-heap(12319): Forcing collection of SoftReferences
for 58369314-byte allocation__
  __12-18 18:20:26.916: E/dalvikvm-heap(12319): Out of memory on a 58369314-byte
allocation.


Ко всему прочему, предел файла меняется в зависимости от устройства.

Код:

  @Override
        protected Boolean doInBackground(String...  params) {
            //В этом методе происходит загрузка файла через
            //стандартный класс URLConnection
            int count;

            try {
                int i=0;
                dataFiles = getResources().getStringArray(R.array.dataFiles);  
                File path = new File(Environment.getExternalStorageDirectory()+"/testing");
                if(!path.exists()){
                    path.mkdirs();
                }
                for (String url_string : params) {
                    URL url = new URL(url_string);
                    URLConnection conection = url.openConnection();
                    conection.connect();
                    int lenghtOfFile = conection.getContentLength();
                    InputStream input = new BufferedInputStream(url.openStream(),
lenghtOfFile);
                    OutputStream output = new FileOutputStream(path+"/"+dataFiles[i]);
                    byte data[] = new byte[256];     
                    long total = 0;
                    while ((count = input.read(data)) != -1) {                   
                        //Проверяем, актуальна ли еще задача
                        if (isCancelled()){
                             output.flush(); 
                            output.close();
                            input.close();
                            return null;
                        }
                        total += count;  
                        output.write(data, 0, count);

                        //Информирование о закачке.
                        //Передаем число, отражающее процент загрузки файла
                        //После вызова этого метода автоматически будет вызван
                        //onProgressUpdate в главном потоке
                        publishProgress((int)((total*100)/lenghtOfFile));
                    }
                    output.flush(); 
                    output.close();
                    input.close();
                    ++i;
                }
            } catch (Exception e) {
                System.out.println("Ошибка: "+e.getMessage()); 
            }


            return true;
        }


Подскажите, пожалуйста, как все-таки возможно качать большие файлы, без того, чтобы
съесть всю кучу?
    


Ответы

Ответ 1



Не понятно, зачем вы используете BufferedInputStream при загрузке данных фиксированного размера из сети, и сохранения их сразу в файл, что не имеет никакого смысла, и при этом не оборачиваете FileOutputStream в BufferedOutputStream, что должно значительно снизить тормоза, в случае медленной ФС, и быстрого интернет-соединения. Попробуйте сделать наоборот.

Ответ 2



Я когда использовал в своем приложении, то делал наподобие вот этого DOWNLOAD LARGE FILES. Попробуйте этот код, если не выйдет - пишите, придумаем что-то. Сейчас нету возможности проверить код.