Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2009.05.31;
Скачать: CL | DM;

Вниз

Web Server Application +CGI + Cookie   Найти похожие ветки 

 
Dennis I. Komarov ©   (2009-03-02 12:00) [0]

Пусть имеем простое cgi-приложение на базе WSA.
Вопрос собственно такой, как научить его работать с куками, ведь операции с ними на уровне HTTP?

У кого есть хороший мануал по этому поводу...


 
Ega23 ©   (2009-03-02 12:17) [1]

RFC 2616   :)


 
Dennis I. Komarov ©   (2009-03-02 12:22) [2]


> Ega23 ©   (02.03.09 12:17) [1]

2965 если не ошибаюсь... ;)


 
Dennis I. Komarov ©   (2009-03-03 13:16) [3]

Ну все же кто работал с cgi и куками?

Пусть будем делать простейший механизм авторизации:
форма, которая пересылает нам (POST) логин и пароль; получив эти данные на валидность и если все тип-топ мы должны передать ответ клиенту в котором послать что-то вроде:
HTTP/1.1 200 OK
... {bla-bla-bla}
Set-Cookie: sessionID=678893467800; path=/; domain=.mydomain.com
...

Но сие деяние должно быть отправлено не моим cgi, а http-сервером(в частности Apache);

Вопрос: как мое cgi должно сказать ему об этом?


 
Ega23 ©   (2009-03-03 13:27) [4]


> Но сие деяние должно быть отправлено не моим cgi, а http-
> сервером(в частности Apache);
>
> Вопрос: как мое cgi должно сказать ему об этом?
>


Да ну? Это как раз cgi должно отправить.
В голом виде примерно так:

program CgiVars;

{$APPTYPE CONSOLE}

uses
 Windows;

const
  VarList: array [1..17] of string [30] =
    ("SERVER_NAME", "SERVER_PROTOCOL",
    "SERVER_PORT", "SERVER_SOFTWARE",
    "GATEWAY_INTERFACE", "REQUEST_METHOD",
    "PATH_TRANSLATED", "HTTP_REFERER",
    "SCRIPT_NAME", "PATH_INFO",
    "QUERY_STRING", "HTTP_ACCEPT",
    "REMOTE_HOST", "REMOTE_USER",
    "REMOTE_ADDR", "REMOTE_IDENT",
    "HTTP_USER_AGENT");

 var
  I: Integer;
  ReqVar: string;
  VarValue: array [0..200] of Char;

begin
 writeln("Content type: text/html");
 writeln;
 writeln("<HTML><HEAD>");
 writeln("<TITLE>CGI Variables</TITLE>");
 writeln("</HEAD><BODY>");
 writeln("<H1>CGI Variables</H1>");
 writeln("<HR><PRE>");

 for I := Low (VarList) to High (VarList) do
  begin
  ReqVar := VarList[I];
  if (GetEnvironmentVariable (PChar(ReqVar),
  VarValue, 200) > 0) then
  else
  VarValue := "";
  writeln (VarList[I] + " = " + VarValue);
  end;
 writeln("</PRE></BODY></HTML>");
end.


Вот и пихаешь туда своё Set-Cookie


 
Dennis I. Komarov ©   (2009-03-03 13:52) [5]

Ну и скажи после этого, что ответ (http) генерирует цги а не сервак ;)
только в какую переменную пихать - не понял :(


 
Ega23 ©   (2009-03-03 14:07) [6]


> Ну и скажи после этого, что ответ (http) генерирует цги
> а не сервак ;)


CGI его генерирует. Убери из него writeln("Content type: text/html"); - и всё. Приплыли.
В случае голого CGI, сервак выступает исключительно транслятором:
1. Получил от браузера HttpRequest
2. Распарсил его.
3. Если такой cgi нет - ответил ошибку (404, ЕМНИП)
4. То, что пришло как GET - запихнул в переменные окружения для cgi
5. Запустил cgi
6. То, что пришло как POST - запихнул в StdIn для cgi
7. Дождался окончания выполнения cgi, вычитал всё из StdOut (или StdErr)
8. Если не дождался - ответил ошибку (по тайм-ауту, код не помню)
9. Если дождался - ответил ровно то, что в StdOut (StdErr) было.
10. Если ответ неправильный (заголовок кривой, данные фиговые и т.п.) - браузер выдаёт ошибку запрашиваемой страницы.


 
забылпароль   (2009-03-03 14:08) [7]

Response: TWebResponse ?


 
Ega23 ©   (2009-03-03 14:09) [8]

Дальше уже могут быть нюансы. Например, работа с cgi "обвязана" надстройкой в виде PHP. Но тут уже другая карусель.


 
забылпароль   (2009-03-03 14:17) [9]

или я что-то не догоняю..

new- wsa - cgi
webmodule1 - newaction
WebActionItem1 - onaction

procedure TWebModule1.WebModule1WebActionItem1Action(Sender: TObject;
 Request: TWebRequest; Response: TWebResponse; var Handled: Boolean);
begin
 Handled := False; { adding a cookie does not handle the request }
 with Response.Cookies.Add do
 begin
   Name := "LastPassword";
   { Set the LastPassword cookie to the current authorization }
   { Or, if no authorization was supplied this time, carry over }
   { the authorization from the LastPassword cookie of the request }
   Value := Request.Authorization;
   if Value = "" then
     Value :=  Request.CookieFields.Values("LastPassword");

   Secure := True; { be sure to use a secure connection!!!!}
   Expires := Now + 1; { this cookie expires in one day }

end;


 
Ega23 ©   (2009-03-03 14:27) [10]


> забылпароль   (03.03.09 14:17) [9]
>
> или я что-то не догоняю..
>


Ну это уже Delphi-обёртка. Если ты этот Responce перед отправкой в строку развернёшь, то увидишь как раз что-то типа


Content-type: text/html;

({reqStatus:1,loginData:{lb_login:"Пользователь",lb_pwd:"Пароль",btn_loginOK:"Вх од"},langInfo:{lngData:[{sn:"EN",fn:"English",lid:2},{sn:"RU",fn:"Russian",lid:1 }],currLID:1}})


 
Ega23 ©   (2009-03-03 14:29) [11]

Это... На ответ не пугайтесь, это в JSON-формате на AJAX-запрос.


 
Dennis I. Komarov ©   (2009-03-03 14:31) [12]

ладно, сойдемся на том, что Content type: text/html - будет частью http header полученного от cgi :) который всеже отправит http-сервер клиенту ;) ?


 
Ega23 ©   (2009-03-03 14:35) [13]


> ладно, сойдемся на том, что Content type: text/html - будет
> частью http header полученного от cgi :) который всеже отправит
> http-сервер клиенту ;) ?


Отправит. А теперь добавь туда своё Set-Cookie - и всё.


 
Dennis I. Komarov ©   (2009-03-03 16:27) [14]

Олег, спасибо за помощь! Ты откуда такую инфу познал?


 
Ega23 ©   (2009-03-03 16:33) [15]


> Олег, спасибо за помощь! Ты откуда такую инфу познал?


Долгая история. Если вкратце, то нечто подобное сейчас в проекте используется. Только вместо CGI там FastCGI крутится.
А так - гугл, RFC, всякая документация и эксперименты, эксперименты, эксперименты...   :)

З.Ы. Не забывай после HttpResponceHeader-а два #10 вставлять. Что-то типа

function CreateJSONHeader : string;
begin
 Result := "Content-type: text/html;"+#10#10;
end;


или


function CreateXMLHeader: string;
begin
 Result := "Content-type: text/xml"+#10#10 +"<?xml version="1.0" encoding="UTF-8"?>";
end;


Ну и за кодировкой внимательно следи - где win-1251, где utf-8


 
Dennis I. Komarov ©   (2009-03-03 16:58) [16]


> З.Ы. Не забывай после HttpResponceHeader-а два #10 вставлять.
>  Что-то типа

Ну логично - заголовок от тела отделяется пустой строкой ;)


 
Ega23 ©   (2009-03-03 17:09) [17]


> Ну логично - заголовок от тела отделяется пустой строкой
> ;)
>


Двумя.  :)
Просто я как-то пол-дня убил - забыл второй #10 поставить. Или лишний запихнул? Не помню уже, почти год наза было.


 
Dennis I. Komarov ©   (2009-03-04 17:31) [18]

Еще вопрос немного в другой огород:
Что правильней хранить в куках для авторизации?


 
Ega23 ©   (2009-03-04 17:38) [19]


> Что правильней хранить в куках для авторизации?


1. Куки могут быть отключены.
2. Если не отключены - храни SessionID. Как его будешь создавать - это уже другой вопрос.


 
Dennis I. Komarov ©   (2009-03-04 17:52) [20]

Мануальчика нет на эту тему?


 
Ega23 ©   (2009-03-04 18:13) [21]


> Мануальчика нет на эту тему?


Нету.
Суть такая.
1. Любое соединение браузера с сервером - одноразовое. Установил соединение, послал запрос, обязательно дождался ответа, если не дождался - убился по таймауту.
2. Соответственно, некий SID (Session ID) ты можешь передать браузеру либо посредством куки (может быть что угодно. Например GUID. Или ещё какая-нибудь псевдоуникальная фигня), либо в виде параметра URL (типа, localhost/fcgi-bin/fcgisrv.exe?SID={3E3ED74A-4BDC-4255-887D-A4CAF36306E2})
3. Далее тебе нужно его "присовокуплять" к твоим действиям. Я, например, запускаю таймер с интервалом в 20 сек., который шлёт через AJAX серверу данный SID. Тот в свою очередь, отслеживает, какой SID когда пришёл. Если больше минуты прошло - сессия убивается.
PHP, к примеру, при настройках по-умолчанию, раздаёт тоже некий SID (по-моему md5(от чего-то-там)). Дальше он его либо в куки пихает, либо автоматом добавляет во все ссылки-формы. Если в течении 24 минут ничего от того браузера не пришло - сессия считается убитой.

В общем, как-то так.


 
Dennis I. Komarov ©   (2009-03-05 09:17) [22]

У меня мылся такая:
- Зашли по HTTP, залогинились, на серваке содали запись а-ля SID, RemoteIP, LoginDateTime, Username, ... (возможно еще чего придет в голову); Соответственно отослали куку на SID, UserName

- При любом следующем запросе чего либо читаем Куку, ищем по ней запись по SID, проверяем совпадение IP и Username, проверяем разницу Now - LoginDateTime (некий таймаут); дальше если все хорошо, обновляем LoginDateTime, если не - отправляем на авторизацию...

Вот вроде так... где какие дыры?


 
Ega23 ©   (2009-03-05 09:51) [23]


> где какие дыры?


У юзверя могут быть отключены куки. По каким-то своим сакральным соображениям. И ты приплыл.


 
Dennis I. Komarov ©   (2009-03-05 11:34) [24]


> И ты приплыл

Почему? Считаем если куки выключены - при запросе куков нету => SID - нету => отправляем на авторизацию

З.Ы. если куков (SID) нету то поля авторизации показывать при попытке чего либо туда запостить. Простые просмотры без авторизации...


 
Ega23 ©   (2009-03-05 11:40) [25]


> Почему? Считаем если куки выключены - при запросе куков
> нету => SID - нету => отправляем на авторизацию


Ага, и так каждый раз?

Про PHP почитай, он в этом плане интересно делает. Как-то определяет, есть куки или нет (как- не помню). Если есть - ставит куку, если нет - добавляет этот SID во все GET-запросы, и, ЕМНИП, как Hidden-поле во все формы.

А почему тебя так смущает передавать SID в качестве параметра URL?


 
Dennis I. Komarov ©   (2009-03-05 11:52) [26]

Интересно, а откуда он узнает этот SID, если куков нету и хранить его негде?


 
Ega23 ©   (2009-03-05 12:08) [27]


> Интересно, а откуда он узнает этот SID, если куков нету
> и хранить его негде?


Это ты про PHP? Ну он его у себя где-то в списке хранит, если инклуд нужный в скрипте выставить, и этот список мониторит по таймауту.
У меня несколько другая система - fastcgi-сервер.
Можно в базе хранить и на уровне базы мониторить.
В общем способов много. Мне изначально была поставлена задача про куки - забыть. Нету их и всё. Поэтому я свой механизм сессий изобрёл.


 
Dennis I. Komarov ©   (2009-03-05 12:43) [28]

не-не я про сторону клиента, он откуда возмет SID чтобы его передать в URL-е или в hidden input?

Вообще как я мыслю:
- Есть кука - передавай SID через него
- нету кука (ну съели аборигены)- авторизируйся при каждом желании чего-нить отправить


 
Ega23 ©   (2009-03-05 12:51) [29]


> не-не я про сторону клиента, он откуда возмет SID чтобы
> его передать в URL-е или в hidden input?


Например, тебя после авторизации должны отправить на страницу
//localhost/cgi-bin/something.cgi
Т.е., фактически, браузер получает то, что сгенерила программа something.cgi
Так вот. При авторизации (успешной) ты его отсылаешь не на
//localhost/cgi-bin/something.cgi , а на
//localhost/cgi-bin/something.cgi?SID={14395DAB-03F6-40ED-B894-46A978A521FF}
Теперь клиент всегда сможет вытащить SID из URL, что-то типа

function GetLocationParam(name) {
 var params = window.location.search.substr(1).split("&");
 for(i=0;i<params.length;i++) {
   var param=params[i].split("=");
   if (param[0]==name) {
     return param[1];
   }
 }  
 return "";
}

function GetCurrSID() {
 var SID = GetLocationParam("SID");
 return SID;
}



и как-то использовать его.

Также, при направлении со страницы авторизации на
//localhost/cgi-bin/something.cgi?SID={14395DAB-03F6-40ED-B894-46A978A521FF}
твоя something.cgi получит этот параметр через переменные окружения.


 
Anatoly Podgoretsky ©   (2009-03-05 12:52) [30]

> Dennis I. Komarov  (05.03.2009 11:52:26)  [26]

А зачем, почему бы не быть просто произвольному идентификатору?
И куки вообще не нужны, передавать как параметр и принимать как параметр, а хранить на сервере, понятие keep-alive


 
Anatoly Podgoretsky ©   (2009-03-05 12:53) [31]

> Dennis I. Komarov  (05.03.2009 12:43:28)  [28]

Глупо и непрофессионально.


 
Ega23 ©   (2009-03-05 12:55) [32]


> - нету кука (ну съели аборигены)- авторизируйся при каждом
> желании чего-нить отправить


Почитай, как реализован механизм сессий в PHP. Станет всё понятно.


 
Dennis I. Komarov ©   (2009-03-05 13:33) [33]


> Anatoly Podgoretsky ©   (05.03.09 12:52) [30]

Не совсем понял механизм... Закрыл - открыл браузер - и все по новой?

> Anatoly Podgoretsky ©   (05.03.09 12:53) [31]

А разве delphimaster не так работает, с той лишь разницей, что кроме всего запостить может и не зарегеный юзер

> Ega23 ©   (05.03.09 12:55) [32]

Да все поиски приводят к phpBB, туды его.


 
Ega23 ©   (2009-03-05 13:44) [34]


> Закрыл - открыл браузер - и все по новой?


Ну вообще-то - да. Или зарегился, перешёл на страницу и ущёл обедать. Вернулся - а сессия уже тю-тю.
Всё неудобство при отключенных куках должно именно к этому сводиться.


 
имя   (2009-03-26 12:08) [35]

Удалено модератором



Страницы: 1 вся ветка

Текущий архив: 2009.05.31;
Скачать: CL | DM;

Наверх




Память: 0.56 MB
Время: 0.014 c
15-1237785548
Б
2009-03-23 08:19
2009.05.31
Ищу 2 книжки по DirectX в Delphi.


15-1238485697
Галинка
2009-03-31 11:48
2009.05.31
маленький вопросик про xampp


15-1238582348
Лёша
2009-04-01 14:39
2009.05.31
Это можно сократить?


2-1239887719
Kolan
2009-04-16 17:15
2009.05.31
TToolButton и Диспетчер драйверов ODBC


2-1239803466
timekiller
2009-04-15 17:51
2009.05.31
Помогите! Якорем IE по балде ..