diff options
Diffstat (limited to 'src/cowboy_http_req.erl')
-rw-r--r-- | src/cowboy_http_req.erl | 79 |
1 files changed, 47 insertions, 32 deletions
diff --git a/src/cowboy_http_req.erl b/src/cowboy_http_req.erl index 539c7f0..3a3dd2f 100644 --- a/src/cowboy_http_req.erl +++ b/src/cowboy_http_req.erl @@ -191,47 +191,62 @@ headers(Req) -> %% returned is used as a return value. %% @see parse_header/3 -spec parse_header(http_header(), #http_req{}) - -> {tokens, [binary()], #http_req{}} - | {undefined, binary(), #http_req{}} - | {error, badarg}. -parse_header('Connection', Req) -> - parse_header('Connection', Req, []); -parse_header(Name, Req) -> - parse_header(Name, Req, undefined). + -> {any(), #http_req{}} | {error, badarg}. +parse_header(Name, Req=#http_req{p_headers=PHeaders}) -> + case lists:keyfind(Name, 1, PHeaders) of + false -> parse_header(Name, Req, parse_header_default(Name)); + {Name, Value} -> {Value, Req} + end. + +%% @doc Default values for semantic header parsing. +-spec parse_header_default(http_header()) -> any(). +parse_header_default('Accept') -> []; +parse_header_default('Accept-Charset') -> []; +parse_header_default('Accept-Encoding') -> []; +parse_header_default('Connection') -> []; +parse_header_default(_Name) -> undefined. %% @doc Semantically parse headers. %% -%% When the header is known, a named tuple is returned containing -%% {Type, P, Req} with Type being the type of value found in P. -%% For example, the header 'Connection' is a list of tokens, therefore -%% the value returned will be a list of binary values and Type will be -%% 'tokens'. -%% -%% When the header is known but not found, the tuple {Type, Default, Req} -%% is returned instead. -%% -%% When the header is unknown, the value is returned directly as an -%% 'undefined' tagged tuple. +%% When the header is unknown, the value is returned directly without parsing. -spec parse_header(http_header(), #http_req{}, any()) - -> {tokens, [binary()], #http_req{}} - | {undefined, binary(), #http_req{}} - | {error, badarg}. -parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default) - when Name =:= 'Connection' -> + -> {any(), #http_req{}} | {error, badarg}. +parse_header(Name, Req, Default) when Name =:= 'Accept' -> + parse_header(Name, Req, Default, + fun (Value) -> + cowboy_http:list(Value, fun cowboy_http:media_range/2) + end); +parse_header(Name, Req, Default) when Name =:= 'Accept-Charset' -> + parse_header(Name, Req, Default, + fun (Value) -> + cowboy_http:nonempty_list(Value, fun cowboy_http:charset/2) + end); +parse_header(Name, Req, Default) when Name =:= 'Accept-Encoding' -> + parse_header(Name, Req, Default, + fun (Value) -> + cowboy_http:list(Value, fun cowboy_http:token_ci/2) + end); +parse_header(Name, Req, Default) when Name =:= 'Connection' -> + parse_header(Name, Req, Default, + fun (Value) -> + cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) + end); +parse_header(Name, Req, Default) -> + {Value, Req2} = header(Name, Req, Default), + {undefined, Value, Req2}. + +parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) -> case header(Name, Req) of - {undefined, Req2} -> {tokens, Default, Req2}; + {undefined, Req2} -> + {Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}}; {Value, Req2} -> - case cowboy_http:nonempty_list(Value, fun cowboy_http:token_ci/2) of + case Fun(Value) of {error, badarg} -> {error, badarg}; P -> - {tokens, P, Req2#http_req{ - p_headers=[{Name, P}|PHeaders]}} + {P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}} end - end; -parse_header(Name, Req, Default) -> - {Value, Req2} = header(Name, Req, Default), - {undefined, Value, Req2}. + end. %% @equiv cookie(Name, Req, undefined) -spec cookie(binary(), #http_req{}) @@ -368,7 +383,7 @@ chunked_reply(Status, Headers, Req=#http_req{socket=Socket, transport=Transport, %% @doc Send a chunk of data. %% %% A chunked reply must have been initiated before calling this function. --spec chunk(iodata(), #http_req{}) -> ok. +-spec chunk(iodata(), #http_req{}) -> ok | {error, atom()}. chunk(_Data, #http_req{socket=_Socket, transport=_Transport, method='HEAD'}) -> ok; chunk(Data, #http_req{socket=Socket, transport=Transport, resp_state=chunks}) -> |