Не так давно я писал про единственную более менее готовую библиотеку OAuth для Delphi, которую хотел использовать в Twitter’e. Проблема её использования заключалась в том, что при отправке сообщений, содержащих русские символы возвращалась ошибка 401. Сегодня эта досадная ошибка была решена. В связи с чем выкладываю в доступ исправленную библиотеку OAuth для Delphi.
Прежде всего, следует указать автора этой библиотеки, т.к. я всего лишь немного доработал её, а не создал с нуля — вот ссылка на его блог. К сожалению, его проект по OAuth уже долгое время не развивается, но кое-какие исходники, при необходимости, вы сможете найти в блоге, в т.ч. и модуль для работы с Twitter’ом с использованием библиотеки.
Теперь, что касается исправлений. Ошибка заключалась в том, что при доступе к ресурсам Twitter’а неверно формировалась строка Base_String. По спецификации OAuth все символы в строке должны быть в кодировке URF-8 и при этом параметры URL (за исключением параметров OAuth) должны располагаться по алфавиту. Кодирование строки проводилось следующим образом:
base := 'POST&' + TOAuthUtil.urlEncodeRFC3986(URL) + '&' + UrlEncode(encodeParams(oParams,'&',false));
В encodeParams кодирование параметров проходило так:
buf := Params.Names[i] + '='+ UrlEncode(Utf8Encode(Params.ValueFromIndex[i])) + ''
Функция UrlEncode выглядит следующим образом:
function UrlEncode(const S : String) : String; var I : Integer; Ch : Char; begin Result := ''; for I := 1 to Length(S) do begin Ch := S[I]; if ((Ch >= '0') and (Ch <= '9')) or ((Ch >= 'a') and (Ch <= 'z')) or ((Ch >= 'A') and (Ch <= 'Z')) or (Ch = '.') or (Ch = '-') or (Ch = '_') or (Ch = '~')then Result := Result + Ch else Result := Result + '%' + IntToHex(Ord(Ch), 2); end; end;
В результате при кодировании любого русского символа получалась следующая картина:
символ
П = %D0%9F
оказывался в Base String как:
%2541F%25440
А при отправке POST-запроса снова как
%D0%9F
В результате чего сервер и возвращал нам 401 ошибку.
Я немного видоизменил кодирование параметров в Base String и использовал вместо UrlEncode немного измененную функцию из Synapse — EncodeTriplet:
function EncodeTriplet(const Value: AnsiString; Delimiter: AnsiChar; Specials: TSpecials): AnsiString; var n, l: Integer; s: AnsiString; c: AnsiChar; begin SetLength(Result, Length(Value) * 3); l := 1; for n := 1 to Length(Value) do begin c := Value[n]; if c in Specials then begin Result[l] := Delimiter; Inc(l); s := IntToHex(Ord(c), 2); Result[l] := s[1]; Inc(l); Result[l] := s[2]; Inc(l); end else begin Result[l] := c; Inc(l); end; end; Dec(l); SetLength(Result, l); end;
Где TSpecials — множество:
type TSpecials = set of AnsiChar; const URLSpecialChar: TSpecials = [#$00..#$20, '<', '>', '"', '%', '{', '}', '|', '\', '^', '~', '[', ']', '`', #$7F..#$FF];
Проверил работу библиотеки, отправив сообщения в Twitter, используя методы API update и direct_messages/new — сообщения отправились без проблем, в т.ч. и сообщения, содержащие в нике пользователя или в тексте спец. символы.
Теперь можете скачивать доработанную библиотеку, скачивать с блога автора модуль для Twitter’а и создавать свои приложения для Twitter в Delphi.
На всякий случай приведу ссылки, которые могу быть Вам полезны:
1. Репозиторий с первоначальным исходником библиотеки (не обновлялся более года)
2. Блог автора проекта OAuthDelphi
3. Пост в моем блоге по использованию библиотеки.

Twitter OAuth и русские символы. Решено. | Delphi в Internet…
Thank you for submitting this cool story — Trackback from progg.ru…
Не работает закачка с iFolder
проверил. всё работает
Перезалей пожалуйста на другой файлоообменник, невозможно скачать от сюда
Ссылка на скачивание архива внизу поста (архив лежит на хостинге блога)
Привет, Влад!
Занялся тут написанием проги под твиттер. возник следющий вопрос. Взял твой модуль OAuth с кириллицей. Все хорошо, все работает (тебе, к стати спасибо за это). Одно «НО» не хочет восклицательный знак отправлять сразу «401» ошибка и хоть ты тресни… Не подскажешь, как можно эту проблему решить?
Ах, да, чуть не забыл, я с Indy (может это важно) использую версию. Т.к. только недавно с Indy разобрался, и нет желания с новой библиотекой разбираться
А, все, видно погорячился тревогу бить, добавил «?»,»!»,»#»,»@» (всЕ, которые не работали) в Specials все заработало.
Сорри за беспокойство!
Да я особенно не встревожился :) Всегда пожалуйста
Vlad, почему-то не отправляется символ #. Не подскажешь в чем может быть дело?
ildild смотри мой предыдущий комент,
«А, все, видно погорячился тревогу бить, добавил «?»,»!»,»#»,»@» (всЕ, которые не работали) в Specials все заработало.
Сорри за беспокойство!»
Леха, а можешь скинуть свой Oauth.pas. Т.к. как я уже написал на форуме, если добавить эти символы в Specials именно в таком виде, то у меня ноль реакции(как не отправлялись так и не отправляются). Если же я добавляю их ASCII коды(напр #=#$23), то эти символы нормально отправляются, но перестают отправляться другие(напр ‘:’ или точка). Вообщем я хз почему так)
Можно ещё вот так переписать UrlEncode
function TForm1.UrlEncode(const S : String) : String;
var
i : integer;
u : ansistring;
r : ansistring;
begin
r := »;
u := ansistring(UTF8Encode(S));
for i := 1 to Length(u) do
begin
case u[i] of
‘A’..’Z’, ‘a’..’z’, ‘0’..’9′, ‘-‘, ‘_’, ‘.’:
r := r + u[i];
else
r := r + ‘%’ + ansistring(IntToHex(Ord(u[i]), 2));
end;
end;
Result := string(r);
end;
Можно ещё вот так переписать UrlEncode и русские буквы будут нормально отправляться
function UrlEncode(const S : String) : String;
var
i : integer;
u : ansistring;
r : ansistring;
begin
r := '';
u := ansistring(UTF8Encode(S));
for i := 1 to Length(u) do
begin
case u[i] of
'A'..'Z', 'a'..'z', '0'..'9', '-', '_', '.':
r := r + u[i];
else
r := r + '%' + ansistring(IntToHex(Ord(u[i]), 2));
end;
end;
Result := string(r);
end;
[…] Twitter OAuth и русские символы. Решено. | Delphi в Internet к записи OAuth, Twitter и русские символы. […]