Http-заголовки расскажут многое о вашем девайсе

в 12:06, , рубрики: http, http request, mobile device, wapstart, мобильное устройство

Http заголовки расскажут многое о вашем девайсе
Если правильно собирать и интерпретировать заголовки, то можно сказать очень многое об устройстве, а возможно и о самом пользователе. В этой статье я расскажу как мы в Wapstart используем сведения, передаваемые в http-заголовках.
Дисклаймер — статья носит обзорный характер. Некоторые вещи могут показаться сообществу слишком "капитанистыми".

Начну с основ:
Как правило, внутри веба взаимодействие производит по протоколу http.


Минимальный валидный http запрос методом GET выглядит так:


GET / HTTP/1.0rn
rn

или так:


GET / HTTP/1.1rn
Host: wapstart.rurn
rn

Заголовок — это пара: наименование поля и его значение, разделенные двоеточием. Подробнее — в rfc.
Как правило, браузеры передают некоторые дополнительные заголовки, которые могут быть описаны в rfc, а могут и не быть. :)
Почти всегда будет передан заголовок User-agent, при работе через прокси так же будут добавлены заголовки via или x-forwarder-for. Строго говоря, rfc не запрещает вам передавать свои заголовки, он просто говорит, что их следует игнорировать.
Например, вот такой запрос все еще валиден:


GET / HTTP/1.1rn
Host: wapstart.rurn
User-agent: dovgrn
x-ololo: trololorn
x-habrauser: dovgrn
rn

В ваше приложение заголовки попадут скорее всего уже в виде, который определется в rfc на cgi протокол. (раздел 4.1)
Грубо говоря, к ним добавится указание протокола (HTTP), они будут переведены в верхний регистр, а минусы (дефисы) будут заменены на знак нижнего подчеркивания: x-habrauser превратится в HTTP_X_HABRAUSER, например. Значения при этом изменений не претерпят.
В реальном мире очень много дополнительных заголовков добавляет opera-mini, а так же стандартный браузер телефонов Nokia.

Вернемся к нашим задачам.
Мы занимаемся рекламой в мобильном вебе, поэтому одна из наших первоочередных задач — это отделение условно «мобильных пользователей» от немобильных.
Само собой, данная задача не может быть решена со 100% эффективностью, т.к. информация формируется на стороне клиента, а как мы знаем, никаким пользовательским данным нельзя доверять.

Помимо определения «мобильности» пользователя, мы хотим знать следующее:

  • информация об устройстве пользователя (разрешение экрана, наличие wifi и т.д.);
  • операционная система, которая управляет устройством;
  • браузер (приложение) из которого сделан запрос.

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

Начнем с первой цели — как понять «мобильность» пользователя. Когда-то давным-давно мы написали такой скрипт.
Я привожу реализацию на php, но используемые тут алгоритмы настолько тривиальны, что скрипт может быть портирован хоть в конфиг nginx. У нас, кстати, была идея делать это на уровне nginx, но до ее реализации руки так и не дошли.
В этой статье код я приводить не буду, он есть на github. Важная ремарка — целиком и полность доверять только одному user-agent нельзя!

Для остальных задач мы придумали базу gdi (Get Device Info), которая в настоящее время умеет доставать информацию об устройстве, os и браузере по совокупности http заголовков.
Для нас интерфейс выглядит следующим образом —


get header:HTTP_ACCEPT_ENCODING=gzip%2C+deflate&HTTP_USER_AGENT=Opera%2F9.80+%28J2ME%2FMIDP%3B+Opera+Mini%2F6.24093%2F27.1324%3B+U%3B+ru%29+Presto%2F2.8.119+Version%2F11.10&HTTP_X_OPERAMINI_FEATURES=advanced%2C+file_system%2C+camera%2C+touch%2C+folding%2C+routing&HTTP_USER_AGENT=LG+%23+KP500&HTTP_USER_AGENT=LG-KP500+Teleca%2FWAP2.0+MIDP-2.0%2FCLDC-1.1
VALUE header:HTTP_ACCEPT_ENCODING=gzip%2C+deflate&HTTP_USER_AGENT=Opera%2F9.80+%28J2ME%2FMIDP%3B+Opera+Mini%2F6.24093%2F27.1324%3B+U%3B+ru%29+Presto%2F2.8.119+Version%2F11.10&HTTP_X_OPERAMINI_FEATURES=advanced%2C+file_system%2C+camera%2C+touch%2C+folding%2C+routing&HTTP_USER_AGENT=LG+%23+KP500&HTTP_USER_AGENT=LG-KP500+Teleca%2FWAP2.0+MIDP-2.0%2FCLDC-1.1 0 234
O:12:"CuttedDevice":6:{s:5:"*id";i:3027;s:7:"*name";s:5:"KP500";s:10:"*deleted";b:0;s:9:"*parent";O:18:"CuttedDeviceParent":2:{s:5:"*id";i:23;s:7:"*name";s:2:"LG";}s:14:"*screenWidth";i:240;s:15:"*screenHeight";i:400;}

//Да, нам удобен протокол memcache ;)
//На самом деле внутри этого чуда совсем не memcache, но это уже отдельная история.

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

Известные проблемы, которые мы пока не можем решить:

  • Apple устройства (Iphone, Ipad, Ipod) передают только сведения о версии операционной системы, но не о модели устройства. Другими словами, имея http запрос из стандартного браузера нельзя сказать с какого Iphone он сделан. С точки зрения передаваемых заголовков 3gs и 4g будут выглядеть одинаково. Да, мы знаем, что это можно решить средствами js.
  • Некоторые сборки opera-mini режут (заменяют) всю информацию о телефоне.


Ну и напоследок немного статистики по заголовкам в нашей базе:


gdi=> select count(distinct name) from request;
 count 
-------
   134
(1 row)


gdi=> select count(*) from request;
 count  
--------
 651655
(1 row)


gdi=> select name, count(value) as different_values from request group by name order by different_values desc limit 10;
           name            | different_values 
---------------------------+------------------
 HTTP_USER_AGENT           |           648494
 HTTP_X_WAP_PROFILE        |              701
 HTTP_X_OPERAMINI_PHONE_UA |              698
 HTTP_VIA                  |              572
 HTTP_X_PROXY_ID           |              245
 HTTP_X_OPERAMINI_FEATURES |              184
 HTTP_X_OPERAMINI_PHONE    |              109
 HTTP_X_MSISDN             |               96
 HTTP_X_BLUECOAT_VIA       |               84
 HTTP_X_DEVICE_USER_AGENT  |               77
(10 rows)

Автор:

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js