Permalink
Browse files

Virtual Directory support. ARG record and CGI variable changes

git-svn-id: https://erlyaws.svn.sourceforge.net/svnroot/erlyaws/trunk/yaws@1093 9fbdc01b-0d2c-0410-bfb7-fb27d70d8b52
  • Loading branch information...
1 parent b3a3035 commit 4ad410187cb269c63ecc41f79bcb31f7faca1b7c @jonhen jonhen committed Feb 23, 2007
Showing with 854 additions and 214 deletions.
  1. +21 −3 include/yaws.hrl
  2. +14 −10 include/yaws_api.hrl
  3. +59 −25 src/yaws_cgi.erl
  4. +704 −176 src/yaws_server.erl
  5. +56 −0 src/yaws_vdir.erl
View
@@ -196,14 +196,32 @@
%% this internal record is used and returned by the URL path parser
+%<JMN_2007-02>
+%!todo - document this record and its usage more.
+% - is it really a win to store 'unflat' strings when they are generally quite short?
+% - we end up having to flatten at various points anyway, so I think in general they should just be stored flat.
+%
+% As an example of the problems - deliver_302 only handles flat paths, but I've seen it being passed #urltype.path
+% directly. Elsewhere I see urltype.path being written to in nested form.
+% WHEN is it being flattened? I don't know for sure that the unflat path could ever get to the deliver_302 but it sure
+% looks like a bug waiting to happen.
+%
+% I understand that for big strings, they can be passed over sockets etc unflattened and it gives a performance gain.
+% For URLs & filesystem paths however (which are generally reasonably short)
+% - I think a canonical flat form is best for code maintainability and reliability
+% - and perhaps also for performance - as it saves having to check for nestedness all over the place.
+%
+%
+%</JMN_2007-02>
+
-record(urltype, {type, %% error | yaws | regular | directory |
- %% forbidden | appmod
+ %% forbidden | appmod
finfo,
path = [],
- fullpath = [], %% deep list
+ fullpath = [], %% deep list (WHY?)
dir = [], %% relative dir where the path leads to
%% flat | unflat need flat for authentication
- data, %% Binary | FileDescriptor | DirListing | undefined
+ data, %% type-specific e.g: Binary | FileDescriptor | DirListing | undefined
deflate, %% undefined | Binary | dynamic
mime = "text/html", %% MIME type
getpath, %% as GET'ed by client
View
@@ -7,26 +7,30 @@
-author('klacke@hyber.org').
-
-record(arg, {
clisock, %% the socket leading to the peer client
client_ip_port, %% {ClientIp, ClientPort} tuple
headers, %% headers
req, %% request
clidata, %% The client data (as a binary in POST requests)
- server_path, %% The normalized server path
- querydata, %% Was the URL on the form of ...?query (GET reqs)
- appmoddata, %% the remainder of the path leading up to the query
- docroot, %% where's the data
+ server_path, %% The normalized server path (pre-querystring part of URI)
+ querydata, %% For URIs of the form ...?querydata
+ %% equiv of cgi QUERY_STRING
+ appmoddata, %% (deprecated - use pathinfo instead) the remainder of the path leading up to the query
+ docroot, %% Physical base location of data for this request
+ docroot_mount, %% virtual directory e.g /myapp/ that the docroot refers to.
fullpath, %% full deep path to yaws file
- cont, %% Continuation for chunked multipart uploads
+ cont, %% Continuation for chunked multipart uploads
state, %% State for use by users of the out/1 callback
pid, %% pid of the yaws worker process
opaque, %% useful to pass static data
- appmod_prepath, %% path in front of: <appmod><appmoddata>
- pathinfo %% Set to 'd/e' when calling c.yaws for the request
- %% http://some.host/a/b/c.yaws/d/e
- }).
+ appmod_prepath, %% (deprecated - use prepath instead) path in front of: <appmod><appmoddata>
+ prepath, %% Path prior to 'dynamic' segment of URI.
+ %% ie http://some.host/<prepath>/<script-point>/d/e
+ %% where <script-point> is an appmod mount point, or .yaws,.php,.cgi etc script file.
+ pathinfo %% Set to '/d/e' when calling c.yaws for the request http://some.host/a/b/c.yaws/d/e
+ %% equiv of cgi PATH_INFO
+ }).
-record(http_request, {method,
View
@@ -185,14 +185,32 @@ cgi_env(Arg, Scriptfilename, Pathinfo, ExtraEnv, SC) ->
{Hostname, Hosttail}=lists:splitwith(fun(X)->X /= $: end,
checkdef(H#headers.host)),
Hostport = case Hosttail of
-
[$: | P] -> P;
[] -> integer_to_list(SC#sconf.port)
end,
PeerAddr = get_socket_peername(Arg#arg.clisock),
LocalAddr = get_socket_sockname(Arg#arg.clisock),
- Scriptname = deep_drop_prefix(Arg#arg.docroot, Arg#arg.fullpath),
+ %Scriptname = deep_drop_prefix(Arg#arg.docroot, Arg#arg.fullpath),
+ %SCRIPT_NAME is the path of the script relative to the root of the website.
+ %just dropping docroot from the fullpath does not give the full SCRIPT_NAME path if a 'vdir' is involved.
+ UriTail = deep_drop_prefix(Arg#arg.docroot, Arg#arg.fullpath),
+ case Arg#arg.docroot_mount of
+ "/" ->
+ %no arg.docroot_mount means that arg.docroot corresponds to the URI-root of the request "/"
+ Scriptname = UriTail;
+ Vdir ->
+ Scriptname = Vdir ++ string:strip(UriTail,left,$/)
+ end,
+
+ Pathinfo2 = checkdef(Pathinfo),
+ case Pathinfo2 of
+ "" ->
+ PathTranslated = "";
+ _ ->
+ %determine what physical path the server would map Pathinfo2 to if it had received just Pathinfo2 in the request.
+ PathTranslated = yaws_server:mappath(SC,Arg,Pathinfo2)
+ end,
%Pass auth info in environment - yes - including password in plain text.
@@ -235,36 +253,51 @@ cgi_env(Arg, Scriptfilename, Pathinfo, ExtraEnv, SC) ->
([
{"SERVER_SOFTWARE", "Yaws/"++yaws_generated:version()},
{"SERVER_NAME", Hostname},
+ {"HTTP_HOST", Hostname},
{"GATEWAY_INTERFACE", "CGI/1.1"},
- {"SERVER_PROTOCOL",
- lists:flatten(
- ["HTTP/",integer_to_list(Maj),".",integer_to_list(Min)])},
+ {"SERVER_PROTOCOL", "HTTP/" ++ integer_to_list(Maj) ++ "." ++ integer_to_list(Min)},
{"SERVER_PORT", Hostport},
{"REQUEST_METHOD", yaws:to_list(R#http_request.method)},
{"REQUEST_URI", RequestURI},
- {"DOCUMENT_ROOT", Arg#arg.docroot},
- {"PATH_INFO", checkdef(Pathinfo)},
+ {"DOCUMENT_ROOT", Arg#arg.docroot},
+ {"DOCUMENT_ROOT_MOUNT", Arg#arg.docroot_mount},
{"SCRIPT_FILENAME", Scriptfilename}, % For PHP 4.3.2 and higher
- % see http://bugs.php.net/bug.php?id=28227
- % (Sergei Golovan).
- {"PATH_TRANSLATED", Scriptfilename}, % This seems not to
- % correspond to the
- % documentation I have
- % read, but it works
- % with PHP.
- %
- % (Not with PHP 4.3.10-16) from
- % Debian sarge (Sergei Golovan).
+ % see http://bugs.php.net/bug.php?id=28227
+ % (Sergei Golovan).
+ % {"SCRIPT_TRANSLATED", Scriptfilename}, %IIS6+
+ {"PATH_INFO", Pathinfo2},
+ {"PATH_TRANSLATED", PathTranslated},
+ %<JMN_2007-02>
+ % CGI/1.1 spec says PATH_TRANSLATED should be NULL or unset if PATH_INFO is NULL
+ % This is in contrast to IIS behaviour - and may break some apps.
+ % broken apps that expect it to always correspond to path of script
+ % should be modified to use SCRIPT_FILENAME instead - or be wrapped.
+ %</JMN_2007-02>
+ %--------------------
+ % <pre_2007-02_comments>
+ % This seems not to
+ % correspond to the
+ % documentation I have
+ % read, but it works
+ % with PHP.
+ %
+ % (Not with PHP 4.3.10-16) from
+ % Debian sarge (Sergei Golovan).
+ % </pre_2007-02_comments>
+ %---------------------
{"SCRIPT_NAME", Scriptname},
- %{"REMOTE_HOST", ""}, We SHOULD send this
{"REMOTE_ADDR", PeerAddr},
+ {"REMOTE_HOST", PeerAddr}, % We SHOULD send this
+ % Resolving DNS not practical for performance reasons
+ % - at least on 1st contact from a particular host.
+ % we could do background lookup so that it's available for subsequent invocations,
+ % but it hardly seems worthwhile. We are permitted by the CGI/1.1 spec to substitute REMOTE_ADDR
{"SERVER_ADDR", LocalAddr}, %Apache compat
{"LOCAL_ADDR", LocalAddr}, %IIS compat
{"QUERY_STRING", checkdef(Arg#arg.querydata)},
{"CONTENT_TYPE", H#headers.content_type},
{"CONTENT_LENGTH", H#headers.content_length},
{"HTTP_ACCEPT", H#headers.accept},
- {"HTTP_HOST", host(H#headers.host)},
{"HTTP_USER_AGENT", H#headers.user_agent},
{"HTTP_COOKIE", flatten_val(make_cookie_val(H#headers.cookie))}
]++lists:map(fun({http_header,_,Var,_,Val})->{tohttp(Var),Val} end,
@@ -281,13 +314,14 @@ tohttp_c(C) when C >= $a , C =< $z ->
tohttp_c(C) ->
C.
+%JMN - apparently redundant. host/1 was being used in cgi_env/5 when Hostname had already been split out of Host.
%% Get Host part from a host string that can contain host or host:port
-host(Host) ->
- case string:tokens(Host, ":") of
- [Hostname, _Port] -> Hostname;
- [Hostname] -> Hostname;
- _Other -> Host
- end.
+%host(Host) ->
+% case string:tokens(Host, ":") of
+% [Hostname, _Port] -> Hostname;
+% [Hostname] -> Hostname;
+% _Other -> Host
+% end.
make_cookie_val([]) ->
Oops, something went wrong.

0 comments on commit 4ad4101

Please sign in to comment.